From 8275fda9b5948975f1913fe9af6676a920bf34ba Mon Sep 17 00:00:00 2001 From: John Goerzen Date: Tue, 21 Jun 2005 13:49:30 +0000 Subject: [PATCH] Import upstream gpsbabel version 1.2.4 --- COPYING | 339 + ChangeLog | 17 + Makefile | 289 + README | 983 + README.contrib | 40 + README.igc | 127 + README.magnav | 28 + README.mapconverter | 35 + README.psp | 112 + README.xmapwpt | 66 + arcdist.c | 165 + brauniger_iq.c | 279 + cetus.c | 427 + chkdoc | 43 + coldsync/Artistic | 131 + coldsync/Makefile | 38 + coldsync/README | 211 + coldsync/README.gpsbabel | 10 + coldsync/config.h | 8 + coldsync/palm.h | 53 + coldsync/pconn/util.h | 60 + coldsync/pdb.c | 2025 ++ coldsync/pdb.h | 273 + coldsync/util.c | 290 + contrib/correctCoordinates.pl | 100 + contrib/gpx2xfig | 73 + copilot.c | 203 + csv_util.c | 1128 + csv_util.h | 131 + defs.h | 530 + delgpl.c | 124 + doc/Makefile | 7 + doc/babelfront2.eps | 19937 ++++++++++++++++ doc/doc.tex | 991 + duplicate.c | 269 + easygps.c | 274 + filter_vecs.c | 220 + garmin.c | 674 + garmin_tables.c | 217 + garmin_tables.h | 38 + gcdb.c | 341 + geo.c | 298 + geocaching.loc | 1 + geoniche.c | 537 + gpilots.c | 419 + gpsman | 53 + gpsman2 | 75 + gpspilot.c | 258 + gpsutil.c | 151 + gpx.c | 1315 + gpxval | 8 + grtcirc.c | 205 + grtcirc.h | 27 + guibabel | 99 + holux.c | 301 + holux.h | 117 + hsa_ndv.c | 553 + html.c | 265 + igc.c | 905 + intdoc/BraunigerIQformat | 55 + intdoc/MPSformat | 382 + intdoc/SA2003_annotations.txt | 419 + intdoc/SA2005_dump.pl | 156 + internal_styles.c | 559 + jeeps/README | 1 + jeeps/garminusb.h | 58 + jeeps/gps.h | 198 + jeeps/gpsapp.c | 5757 +++++ jeeps/gpsapp.h | 65 + jeeps/gpscom.c | 612 + jeeps/gpscom.h | 45 + jeeps/gpsdatum.h | 206 + jeeps/gpsfmt.c | 1562 ++ jeeps/gpsfmt.h | 27 + jeeps/gpsinput.c | 2253 ++ jeeps/gpsinput.h | 23 + jeeps/gpslibusb.c | 274 + jeeps/gpsmath.c | 1799 ++ jeeps/gpsmath.h | 123 + jeeps/gpsmem.c | 1484 ++ jeeps/gpsmem.h | 88 + jeeps/gpsnmea.h | 312 + jeeps/gpsnmeafmt.h | 44 + jeeps/gpsnmeaget.h | 43 + jeeps/gpsport.h | 16 + jeeps/gpsproj.c | 4485 ++++ jeeps/gpsproj.h | 157 + jeeps/gpsprot.c | 366 + jeeps/gpsprot.h | 276 + jeeps/gpsread.c | 218 + jeeps/gpsread.h | 23 + jeeps/gpsrqst.c | 175 + jeeps/gpsrqst.h | 20 + jeeps/gpssend.c | 219 + jeeps/gpssend.h | 26 + jeeps/gpsserial.c | 650 + jeeps/gpsserial.h | 33 + jeeps/gpsusbread.c | 62 + jeeps/gpsusbsend.c | 55 + jeeps/gpsusbstub.c | 56 + jeeps/gpsusbwin.c | 296 + jeeps/gpsutil.c | 691 + jeeps/gpsutil.h | 48 + jeeps/main.c | 31 + macgpsbabel/Credits.rtf | 47 + macgpsbabel/English.lproj/InfoPlist.strings | Bin 0 -> 616 bytes .../English.lproj/MainMenu.nib/classes.nib | 4 + .../MainMenu.nib/data.dependency | 10 + .../English.lproj/MainMenu.nib/info.nib | 25 + .../English.lproj/MainMenu.nib/objects.nib | Bin 0 -> 22015 bytes macgpsbabel/MacGPSBabel.applescript | 839 + .../MacGPSBabel.pbproj/default.pbxuser | 26 + .../MacGPSBabel.pbproj/jeremya.pbxuser | 1034 + .../MacGPSBabel.pbproj/project.pbxproj | 480 + macgpsbabel/README.macgpsbabel | 8 + macgpsbabel/main.m | 9 + macgpsbabel/mgb.icns | Bin 0 -> 33545 bytes macgpsbabel/preferences.applescript | 185 + magellan.h | 51 + magnav.c | 273 + magproto.c | 1409 ++ main.c | 300 + mapopolis.c | 320 + mapsend.c | 594 + mapsend.h | 44 + mapsource.c | 2174 ++ mingw/Makefile | 26 + mingw/README.expat | 1 + mingw/coldsync/.ignore | 0 mingw/include/expat.h | 713 + mingw/jeeps/.ignore | 0 mingw/lib/libexpat.a | Bin 0 -> 39988 bytes mingw/libexpat.dll | Bin 0 -> 122773 bytes mingw/mkwintesto.c | 456 + mingw/shapelib/.ignore | 0 mingw/testo | 5 + mingw/wintesto.cmd | 875 + mkshort.c | 550 + mkstyle.sh | 21 + msvc/Expat/expat.h | 1001 + msvc/Expat/libexpat.dll | Bin 0 -> 143360 bytes msvc/Expat/libexpat.lib | Bin 0 -> 16816 bytes msvc/GPSBabel.dsp | 645 + msvc/GPSBabel.dsw | 29 + msvc/GPSBabel.sln | 21 + msvc/GPSBabel.vcproj | 1717 ++ msvc/README.msvc | 26 + navicache.c | 267 + netstumbler.c | 304 + nmea.c | 457 + ozi.c | 703 + palmdoc.c | 617 + pcx.c | 277 + polygon.c | 298 + position.c | 372 + psitrex.c | 810 + psp.c | 469 + queue.c | 42 + queue.h | 51 + quovadis.c | 296 + quovadis.h | 123 + reference/GeocachingDB.PDB | Bin 0 -> 5822 bytes reference/Glad_4.exp | Bin 0 -> 19994 bytes reference/Glad_5.exp | 536 + reference/UKultralight.pdb | Bin 0 -> 26248 bytes reference/arcdist_arc.txt | 115 + reference/arcdist_input.txt | 103 + reference/arcdist_output.txt | 11 + reference/cetus.gpu | 9 + reference/cetus.pdb | Bin 0 -> 1095 bytes reference/chicago.trk | Bin 0 -> 58030 bytes reference/dnatest.txt | 16 + reference/dusky.gnuplot | 65 + reference/dusky.trk | 63 + reference/easygps.loc | Bin 0 -> 1378 bytes reference/geoniche.pdb | Bin 0 -> 1422 bytes reference/gl.loc | 56 + reference/gnuplot.style | 26 + reference/gpilots.pdb | Bin 0 -> 2744 bytes reference/gpsdrive.txt | 9 + reference/gpspilot.pdb | Bin 0 -> 609 bytes reference/gu.wpt | 9 + reference/holux.gpx | 46 + reference/holux.wpo | Bin 0 -> 25512 bytes reference/hsandv.exp | 80 + reference/human.in | 7 + reference/humanread.out | 6 + reference/humanread.style | 20 + reference/humanwrite.out | 6 + reference/humanwrite.style | 28 + reference/igc1.gpx | 549 + reference/igc1_3d.out | 123 + reference/igc1_baro.gpx | 2563 ++ reference/igc1_gpx.out | 378 + reference/igc1_igc.out | 123 + reference/igc2.igc | 46 + reference/igc2_gpx.out | 127 + reference/igc2_igc.out | 32 + reference/magfile | 18 + reference/magnav.pdb | Bin 0 -> 1160 bytes reference/magnavr.gpu | 9 + reference/mapsource.mps | Bin 0 -> 1202 bytes reference/mps-empty.mps | Bin 0 -> 52 bytes reference/mxf.mxf | 9 + reference/navicache.ref | 2 + reference/navicache.xml | 91 + reference/netstumbler.mps | Bin 0 -> 4838 bytes reference/netstumbler.txt | 42 + reference/ozi.wpt | 13 + reference/paris.wpo | Bin 0 -> 25600 bytes reference/polygon_allencty.txt | 177 + reference/polygon_output.txt | 37 + reference/ps.psp | Bin 0 -> 964 bytes reference/psitwpts.txt | 17 + reference/quovadis.gpu | 9 + reference/quovadis.pdb | Bin 0 -> 601 bytes reference/radius.csv | 1 + reference/route/magellan.rte | 22 + reference/route/psitrtes.txt | 8 + reference/route/route.gpx | 77 + reference/route/route.mapsend | Bin 0 -> 922 bytes reference/route/route.mps | Bin 0 -> 3182 bytes reference/route/vieac.README | 14 + reference/route/vieac.rte | 173 + reference/simplify_output.txt | 13 + reference/topomapexample.txt | 8 + reference/topomappro.txt | 10 + reference/tpg.tpg | Bin 0 -> 577 bytes reference/track/chi-mapsend.trk | Bin 0 -> 58030 bytes reference/track/i65.anr | Bin 0 -> 14732 bytes reference/track/i65.anr.gpx | 4971 ++++ reference/track/mapsend.trk | Bin 0 -> 1884 bytes reference/track/meridian.trk | 64 + reference/track/mps-track.mps | Bin 0 -> 2056 bytes reference/track/nmea | 894 + reference/track/psittrks.txt | 1142 + reference/track/tracks.gpx | 269 + reference/track/webpark1.gpl | Bin 0 -> 54656 bytes reference/xmap | 4 + reference/xmapwpt.wpt | 9 + reverse_route.c | 67 + route.c | 197 + saroute.c | 281 + shape.c | 200 + shapelib/README.GPSBabel | 4 + shapelib/dbf_api.html | 408 + shapelib/dbfopen.c | 1498 ++ shapelib/shapefil.h | 490 + shapelib/shapelib.html | 334 + shapelib/shp_api.html | 376 + shapelib/shpopen.c | 1872 ++ smplrout.c | 251 + sort.c | 108 + stackfilter.c | 192 + style/README.style | 397 + style/arc.style | 21 + style/csv.style | 23 + style/custom.style | 52 + style/dna.style | 28 + style/fugawi.style | 39 + style/gpsdrive.style | 32 + style/gpsman.style | 34 + style/mapconverter.style | 35 + style/mxf.style | 39 + style/nima.style | 45 + style/s_and_t.style | 36 + style/saplus.style | 28 + style/tabsep.style | 53 + style/xmap.style | 28 + style/xmapwpt.style | 30 + testo | 599 + text.c | 231 + tiger.c | 288 + tmpro.c | 255 + tools/cleardebug | 5 + tools/cvslog | 1 + tools/memdebug | 71 + tools/mkchanges | 15 + torture_test | 27 + tpg.c | 365 + util.c | 1156 + util_crc.c | 81 + vecs.c | 595 + vmem.c | 67 + waypt.c | 288 + win32/README | 5 + win32/gpsbabelfront.dpr | 14 + win32/gpsbabelfront.exe | Bin 0 -> 430080 bytes win32/gpsbabelfront_mainform.dfm | 156 + win32/gpsbabelfront_mainform.pas | 384 + xcsv.c | 573 + 291 files changed, 105974 insertions(+) create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 Makefile create mode 100644 README create mode 100644 README.contrib create mode 100644 README.igc create mode 100644 README.magnav create mode 100644 README.mapconverter create mode 100644 README.psp create mode 100644 README.xmapwpt create mode 100644 arcdist.c create mode 100644 brauniger_iq.c create mode 100644 cetus.c create mode 100644 chkdoc create mode 100644 coldsync/Artistic create mode 100644 coldsync/Makefile create mode 100644 coldsync/README create mode 100644 coldsync/README.gpsbabel create mode 100644 coldsync/config.h create mode 100644 coldsync/palm.h create mode 100644 coldsync/pconn/util.h create mode 100644 coldsync/pdb.c create mode 100644 coldsync/pdb.h create mode 100644 coldsync/util.c create mode 100644 contrib/correctCoordinates.pl create mode 100644 contrib/gpx2xfig create mode 100644 copilot.c create mode 100644 csv_util.c create mode 100644 csv_util.h create mode 100644 defs.h create mode 100644 delgpl.c create mode 100644 doc/Makefile create mode 100644 doc/babelfront2.eps create mode 100644 doc/doc.tex create mode 100644 duplicate.c create mode 100644 easygps.c create mode 100644 filter_vecs.c create mode 100644 garmin.c create mode 100644 garmin_tables.c create mode 100644 garmin_tables.h create mode 100644 gcdb.c create mode 100644 geo.c create mode 100644 geocaching.loc create mode 100644 geoniche.c create mode 100644 gpilots.c create mode 100644 gpsman create mode 100644 gpsman2 create mode 100644 gpspilot.c create mode 100644 gpsutil.c create mode 100644 gpx.c create mode 100644 gpxval create mode 100644 grtcirc.c create mode 100644 grtcirc.h create mode 100644 guibabel create mode 100644 holux.c create mode 100644 holux.h create mode 100644 hsa_ndv.c create mode 100644 html.c create mode 100644 igc.c create mode 100644 intdoc/BraunigerIQformat create mode 100644 intdoc/MPSformat create mode 100644 intdoc/SA2003_annotations.txt create mode 100644 intdoc/SA2005_dump.pl create mode 100644 internal_styles.c create mode 100644 jeeps/README create mode 100644 jeeps/garminusb.h create mode 100644 jeeps/gps.h create mode 100644 jeeps/gpsapp.c create mode 100644 jeeps/gpsapp.h create mode 100644 jeeps/gpscom.c create mode 100644 jeeps/gpscom.h create mode 100644 jeeps/gpsdatum.h create mode 100644 jeeps/gpsfmt.c create mode 100644 jeeps/gpsfmt.h create mode 100644 jeeps/gpsinput.c create mode 100644 jeeps/gpsinput.h create mode 100644 jeeps/gpslibusb.c create mode 100644 jeeps/gpsmath.c create mode 100644 jeeps/gpsmath.h create mode 100644 jeeps/gpsmem.c create mode 100644 jeeps/gpsmem.h create mode 100644 jeeps/gpsnmea.h create mode 100644 jeeps/gpsnmeafmt.h create mode 100644 jeeps/gpsnmeaget.h create mode 100644 jeeps/gpsport.h create mode 100644 jeeps/gpsproj.c create mode 100644 jeeps/gpsproj.h create mode 100644 jeeps/gpsprot.c create mode 100644 jeeps/gpsprot.h create mode 100644 jeeps/gpsread.c create mode 100644 jeeps/gpsread.h create mode 100644 jeeps/gpsrqst.c create mode 100644 jeeps/gpsrqst.h create mode 100644 jeeps/gpssend.c create mode 100644 jeeps/gpssend.h create mode 100644 jeeps/gpsserial.c create mode 100644 jeeps/gpsserial.h create mode 100644 jeeps/gpsusbread.c create mode 100644 jeeps/gpsusbsend.c create mode 100644 jeeps/gpsusbstub.c create mode 100644 jeeps/gpsusbwin.c create mode 100644 jeeps/gpsutil.c create mode 100644 jeeps/gpsutil.h create mode 100644 jeeps/main.c create mode 100644 macgpsbabel/Credits.rtf create mode 100644 macgpsbabel/English.lproj/InfoPlist.strings create mode 100644 macgpsbabel/English.lproj/MainMenu.nib/classes.nib create mode 100644 macgpsbabel/English.lproj/MainMenu.nib/data.dependency create mode 100644 macgpsbabel/English.lproj/MainMenu.nib/info.nib create mode 100644 macgpsbabel/English.lproj/MainMenu.nib/objects.nib create mode 100644 macgpsbabel/MacGPSBabel.applescript create mode 100644 macgpsbabel/MacGPSBabel.pbproj/default.pbxuser create mode 100644 macgpsbabel/MacGPSBabel.pbproj/jeremya.pbxuser create mode 100644 macgpsbabel/MacGPSBabel.pbproj/project.pbxproj create mode 100644 macgpsbabel/README.macgpsbabel create mode 100644 macgpsbabel/main.m create mode 100644 macgpsbabel/mgb.icns create mode 100644 macgpsbabel/preferences.applescript create mode 100644 magellan.h create mode 100644 magnav.c create mode 100644 magproto.c create mode 100644 main.c create mode 100644 mapopolis.c create mode 100644 mapsend.c create mode 100644 mapsend.h create mode 100644 mapsource.c create mode 100644 mingw/Makefile create mode 100644 mingw/README.expat create mode 100644 mingw/coldsync/.ignore create mode 100644 mingw/include/expat.h create mode 100644 mingw/jeeps/.ignore create mode 100644 mingw/lib/libexpat.a create mode 100644 mingw/libexpat.dll create mode 100644 mingw/mkwintesto.c create mode 100644 mingw/shapelib/.ignore create mode 100644 mingw/testo create mode 100644 mingw/wintesto.cmd create mode 100644 mkshort.c create mode 100644 mkstyle.sh create mode 100644 msvc/Expat/expat.h create mode 100644 msvc/Expat/libexpat.dll create mode 100644 msvc/Expat/libexpat.lib create mode 100644 msvc/GPSBabel.dsp create mode 100644 msvc/GPSBabel.dsw create mode 100644 msvc/GPSBabel.sln create mode 100644 msvc/GPSBabel.vcproj create mode 100644 msvc/README.msvc create mode 100644 navicache.c create mode 100644 netstumbler.c create mode 100644 nmea.c create mode 100644 ozi.c create mode 100644 palmdoc.c create mode 100644 pcx.c create mode 100644 polygon.c create mode 100644 position.c create mode 100644 psitrex.c create mode 100644 psp.c create mode 100644 queue.c create mode 100644 queue.h create mode 100644 quovadis.c create mode 100644 quovadis.h create mode 100644 reference/GeocachingDB.PDB create mode 100644 reference/Glad_4.exp create mode 100644 reference/Glad_5.exp create mode 100644 reference/UKultralight.pdb create mode 100644 reference/arcdist_arc.txt create mode 100644 reference/arcdist_input.txt create mode 100644 reference/arcdist_output.txt create mode 100644 reference/cetus.gpu create mode 100644 reference/cetus.pdb create mode 100644 reference/chicago.trk create mode 100644 reference/dnatest.txt create mode 100644 reference/dusky.gnuplot create mode 100644 reference/dusky.trk create mode 100644 reference/easygps.loc create mode 100644 reference/geoniche.pdb create mode 100644 reference/gl.loc create mode 100644 reference/gnuplot.style create mode 100644 reference/gpilots.pdb create mode 100644 reference/gpsdrive.txt create mode 100644 reference/gpspilot.pdb create mode 100644 reference/gu.wpt create mode 100644 reference/holux.gpx create mode 100644 reference/holux.wpo create mode 100644 reference/hsandv.exp create mode 100644 reference/human.in create mode 100644 reference/humanread.out create mode 100644 reference/humanread.style create mode 100644 reference/humanwrite.out create mode 100644 reference/humanwrite.style create mode 100644 reference/igc1.gpx create mode 100644 reference/igc1_3d.out create mode 100644 reference/igc1_baro.gpx create mode 100644 reference/igc1_gpx.out create mode 100644 reference/igc1_igc.out create mode 100644 reference/igc2.igc create mode 100644 reference/igc2_gpx.out create mode 100644 reference/igc2_igc.out create mode 100644 reference/magfile create mode 100644 reference/magnav.pdb create mode 100644 reference/magnavr.gpu create mode 100644 reference/mapsource.mps create mode 100644 reference/mps-empty.mps create mode 100644 reference/mxf.mxf create mode 100644 reference/navicache.ref create mode 100644 reference/navicache.xml create mode 100644 reference/netstumbler.mps create mode 100644 reference/netstumbler.txt create mode 100644 reference/ozi.wpt create mode 100644 reference/paris.wpo create mode 100644 reference/polygon_allencty.txt create mode 100644 reference/polygon_output.txt create mode 100644 reference/ps.psp create mode 100644 reference/psitwpts.txt create mode 100644 reference/quovadis.gpu create mode 100644 reference/quovadis.pdb create mode 100644 reference/radius.csv create mode 100644 reference/route/magellan.rte create mode 100644 reference/route/psitrtes.txt create mode 100644 reference/route/route.gpx create mode 100644 reference/route/route.mapsend create mode 100644 reference/route/route.mps create mode 100644 reference/route/vieac.README create mode 100644 reference/route/vieac.rte create mode 100644 reference/simplify_output.txt create mode 100644 reference/topomapexample.txt create mode 100644 reference/topomappro.txt create mode 100644 reference/tpg.tpg create mode 100644 reference/track/chi-mapsend.trk create mode 100644 reference/track/i65.anr create mode 100644 reference/track/i65.anr.gpx create mode 100644 reference/track/mapsend.trk create mode 100644 reference/track/meridian.trk create mode 100644 reference/track/mps-track.mps create mode 100644 reference/track/nmea create mode 100644 reference/track/psittrks.txt create mode 100644 reference/track/tracks.gpx create mode 100644 reference/track/webpark1.gpl create mode 100644 reference/xmap create mode 100644 reference/xmapwpt.wpt create mode 100644 reverse_route.c create mode 100644 route.c create mode 100644 saroute.c create mode 100644 shape.c create mode 100644 shapelib/README.GPSBabel create mode 100644 shapelib/dbf_api.html create mode 100644 shapelib/dbfopen.c create mode 100644 shapelib/shapefil.h create mode 100644 shapelib/shapelib.html create mode 100644 shapelib/shp_api.html create mode 100644 shapelib/shpopen.c create mode 100644 smplrout.c create mode 100644 sort.c create mode 100644 stackfilter.c create mode 100644 style/README.style create mode 100644 style/arc.style create mode 100644 style/csv.style create mode 100644 style/custom.style create mode 100644 style/dna.style create mode 100644 style/fugawi.style create mode 100644 style/gpsdrive.style create mode 100644 style/gpsman.style create mode 100644 style/mapconverter.style create mode 100644 style/mxf.style create mode 100644 style/nima.style create mode 100644 style/s_and_t.style create mode 100644 style/saplus.style create mode 100644 style/tabsep.style create mode 100644 style/xmap.style create mode 100644 style/xmapwpt.style create mode 100644 testo create mode 100644 text.c create mode 100644 tiger.c create mode 100644 tmpro.c create mode 100644 tools/cleardebug create mode 100644 tools/cvslog create mode 100644 tools/memdebug create mode 100644 tools/mkchanges create mode 100644 torture_test create mode 100644 tpg.c create mode 100644 util.c create mode 100644 util_crc.c create mode 100644 vecs.c create mode 100644 vmem.c create mode 100644 waypt.c create mode 100644 win32/README create mode 100644 win32/gpsbabelfront.dpr create mode 100644 win32/gpsbabelfront.exe create mode 100644 win32/gpsbabelfront_mainform.dfm create mode 100644 win32/gpsbabelfront_mainform.pas create mode 100644 xcsv.c diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..514d6c73f --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..f00532be1 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,17 @@ +Version 1.0.0 + + NEW: Windows support. You must download and install the expat dll + if you do not already have it. Get it from + http://sourceforge.net/projects/mingwrep/ + NEW: '-s' can be used to synthesize shortnames. Handy for geocaching. + NEW: Read and write files for Meridian flash cards. + NEW: Add Cetus support. + NEW: Add partial Gpspilot support. + + FIXED: Bad math in gpsutil. + FIXED: Bad math in Magellan. + FIXED: Various minor bugs. + +Version 0.8.1 + + initial release diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..35ac1039a --- /dev/null +++ b/Makefile @@ -0,0 +1,289 @@ + +# If you do not have libexpat and you have no use for reading any input +# type that is XML-ish (i.e. gpx or geocaching.com's/loc) you can uncomment +# INHIBIT_EXPAT and coment out LIBEXPAT on just to get a build working quickly. +# INHIBIT_EXPAT=-DNO_EXPAT +LIBEXPAT=-lexpat # -lefence + +# USB may required non-standard libraries (like libusb) be installed +# and may not be available on all OSes. Uncomment this to remove the key +# parts of USB from the build. +INHIBIT_USB=-DNO_USB + +# +# Enable either or both of these as you wish. +# +OPTIMIZATION=-O $(EXTRA_OPTIMIZATION) +DEBUGGING=-g $(EXTRA_DEBUGGING) +# add -DDEBUG_MEM to turn on memory allocation logging +CFLAGS=$(EXTRA_CFLAGS) $(DEBUGGING) -Icoldsync $(INHIBIT_EXPAT) $(INHIBIT_USB) $(OPTIMIZATION) +INSTALL_TARGETDIR=/usr/local/ + +FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o garmin_tables.o \ + gpsutil.o pcx.o cetus.o copilot.o gpspilot.o magnav.o \ + psp.o holux.o garmin.o tmpro.o tpg.o \ + xcsv.o gcdb.o tiger.o internal_styles.o easygps.o quovadis.o \ + gpilots.o saroute.o navicache.o psitrex.o geoniche.o delgpl.o \ + ozi.o nmea.o text.o html.o palmdoc.o netstumbler.o hsa_ndv.o \ + igc.o brauniger_iq.o shape.o + +FILTERS=position.o duplicate.o arcdist.o polygon.o smplrout.o reverse_route.o sort.o stackfilter.o + +OSJEEPS=jeeps/gpslibusb.o +JEEPS=jeeps/gpsapp.o jeeps/gpscom.o \ + jeeps/gpsmath.o jeeps/gpsmem.o \ + jeeps/gpsprot.o jeeps/gpsread.o \ + jeeps/gpsrqst.o jeeps/gpssend.o jeeps/gpsserial.o jeeps/gpsutil.o \ + jeeps/gpsusbread.o jeeps/gpsusbsend.o jeeps/gpsusbstub.o $(OSJEEPS) +# Extra modules in Jeeps that we don't use +# jeeps/gpsfmt.o jeeps/gpsinput.o jeeps/gpsproj.o + + +COLDSYNC=coldsync/util.o coldsync/pdb.o + +SHAPE=shapelib/shpopen.o shapelib/dbfopen.o + +LIBOBJS = queue.o route.o waypt.o filter_vecs.o util.o vecs.o mkshort.o \ + csv_util.o grtcirc.o vmem.o util_crc.o \ + $(COLDSYNC) $(GARMIN) $(JEEPS) $(SHAPE) $(FMTS) $(FILTERS) +OBJS = main.o $(LIBOBJS) + +.c.o: + $(CC) -c $(CFLAGS) $< -o $@ + +all: gpsbabel + +gpsbabel: $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -o gpsbabel $(LIBEXPAT) -lm + +main.o: + $(CC) -c $(CFLAGS) -DVERSION=\"$(VERSIOND)\" $< + +clean: + rm -f $(OBJS) gpsbabel gpsbabel.exe + +check: + ./testo + +torture: + ./testo + ./torture_test + +# +# This will only work on UNIX-like substances. +# +install: + install gpsbabel $(INSTALL_TARGETDIR)/bin + +# Nerdy release stuff that needs to work only on Linux. + +leaktest: + make EXTRA_CFLAGS=-DDEBUG_MEM + tools/cleardebug + ./testo + tools/memdebug | grep -v '^command line:' + +dep: + make clean && make CC="gcc -MMD" && cat *.d */*.d > /tmp/dep && rm *.d */*.d + (echo -n "internal_styles.c: mkstyle.sh " ; echo style/*.style ; /bin/echo -e '\t./mkstyle.sh > internal_styles.c || (rm -f internal_styles.c ; exit 1)' ) >> /tmp/dep + echo Edit Makefile and bring in /tmp/dep + +#VERSIONU=1_2_4_beta10162004 +#VERSIOND=1.2.4_beta10162004 +VERSIONU=1_2_4 +VERSIOND=1.2.4 + +release: + cvs commit + ./chkdoc + make clean && cd mingw ; make clean + rm -fr gpsbabel-$(VERSIOND) + cvs tag -F gpsbabel_$(VERSIONU) + cvs export -r gpsbabel_$(VERSIONU) -d gpsbabel-$(VERSIOND) gpsbabel + tar czf /tmp/gpsbabel-$(VERSIOND).tar.gz gpsbabel-$(VERSIOND) + cd /tmp ; tar xzf gpsbabel-$(VERSIOND).tar.gz + touch /tmp/gpsbabel-$(VERSIOND)/internal_styles.c + cd /tmp/gpsbabel-$(VERSIOND)/mingw ; make + curl -u anonymous:anonymous --upload-file /tmp/gpsbabel-$(VERSIOND).tar.gz ftp://upload.sf.net/incoming/ + curl -u anonymous:anonymous --upload-file /tmp/gpsbabel-$(VERSIOND).zip ftp://upload.sf.net/incoming/ + +mac-build: + make LIBEXPAT=/sw/lib/libexpat.a EXTRA_CFLAGS="-I/sw/include" + +mac-release: + mkdir -p usr/bin usr/share/gpsbabel/doc + cp gpsbabel usr/bin/ + cp README* COPYING usr/share/gpsbabel/doc + tar cvzf gpsbabel-osx.tgz usr/bin/gpsbabel + curl -u anonymous:anonymous --upload-file gpsbabel-osx.tgz ftp://upload.sf.net/incoming/ + +# Machine generated from here down. + +arcdist.o: arcdist.c defs.h queue.h grtcirc.h +brauniger_iq.o: brauniger_iq.c defs.h queue.h jeeps/gpsserial.h \ + jeeps/gps.h jeeps/gpsport.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h \ + jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h \ + jeeps/gpsnmeaget.h +cetus.o: cetus.c defs.h queue.h coldsync/palm.h coldsync/pdb.h +copilot.o: copilot.c defs.h queue.h coldsync/palm.h coldsync/pdb.h +csv_util.o: csv_util.c defs.h queue.h csv_util.h grtcirc.h +delgpl.o: delgpl.c defs.h queue.h +duplicate.o: duplicate.c defs.h queue.h +easygps.o: easygps.c defs.h queue.h +filter_vecs.o: filter_vecs.c defs.h queue.h +garmin.o: garmin.c defs.h queue.h jeeps/gps.h jeeps/gpsport.h \ + jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \ + jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \ + jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h jeeps/gpsrqst.h \ + jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h \ + garmin_tables.h +garmin_tables.o: garmin_tables.c garmin_tables.h +gcdb.o: gcdb.c defs.h queue.h coldsync/palm.h coldsync/pdb.h +geo.o: geo.c defs.h queue.h +geoniche.o: geoniche.c defs.h queue.h coldsync/palm.h coldsync/pdb.h +gpilots.o: gpilots.c defs.h queue.h coldsync/palm.h coldsync/pdb.h \ + garmin_tables.h +gpspilot.o: gpspilot.c defs.h queue.h coldsync/palm.h coldsync/pdb.h +gpsutil.o: gpsutil.c defs.h queue.h magellan.h +gpx.o: gpx.c defs.h queue.h +grtcirc.o: grtcirc.c defs.h queue.h +holux.o: holux.c defs.h queue.h holux.h +hsa_ndv.o: hsa_ndv.c defs.h queue.h +html.o: html.c defs.h queue.h jeeps/gpsmath.h jeeps/gps.h jeeps/gpsport.h \ + jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \ + jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \ + jeeps/gpsnmea.h jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h \ + jeeps/gpsproj.h jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h +igc.o: igc.c defs.h queue.h +internal_styles.o: internal_styles.c defs.h queue.h +magnav.o: magnav.c defs.h queue.h coldsync/palm.h coldsync/pdb.h +magproto.o: magproto.c defs.h queue.h magellan.h +main.o: main.c defs.h queue.h +mapsend.o: mapsend.c defs.h queue.h mapsend.h magellan.h +mapsource.o: mapsource.c defs.h queue.h garmin_tables.h +mkshort.o: mkshort.c defs.h queue.h +navicache.o: navicache.c defs.h queue.h +netstumbler.o: netstumbler.c defs.h queue.h csv_util.h +nmea.o: nmea.c defs.h queue.h +ozi.o: ozi.c defs.h queue.h csv_util.h +palmdoc.o: palmdoc.c defs.h queue.h jeeps/gpsmath.h jeeps/gps.h \ + jeeps/gpsport.h jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsnmea.h jeeps/gpsmem.h jeeps/gpsrqst.h \ + jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h \ + coldsync/palm.h coldsync/pdb.h +pcx.o: pcx.c defs.h queue.h garmin_tables.h +polygon.o: polygon.c defs.h queue.h +position.o: position.c defs.h queue.h grtcirc.h +psitrex.o: psitrex.c defs.h queue.h garmin_tables.h +psp.o: psp.c defs.h queue.h +queue.o: queue.c queue.h +quovadis.o: quovadis.c quovadis.h defs.h queue.h coldsync/palm.h \ + coldsync/pdb.h +reverse_route.o: reverse_route.c defs.h queue.h +route.o: route.c defs.h queue.h +saroute.o: saroute.c defs.h queue.h +shape.o: shape.c defs.h queue.h shapelib/shapefil.h +smplrout.o: smplrout.c defs.h queue.h grtcirc.h +sort.o: sort.c defs.h queue.h +stackfilter.o: stackfilter.c defs.h queue.h +text.o: text.c defs.h queue.h jeeps/gpsmath.h jeeps/gps.h jeeps/gpsport.h \ + jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \ + jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \ + jeeps/gpsnmea.h jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h \ + jeeps/gpsproj.h jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h +tiger.o: tiger.c defs.h queue.h csv_util.h +tmpro.o: tmpro.c defs.h queue.h csv_util.h +tpg.o: tpg.c defs.h queue.h jeeps/gpsmath.h jeeps/gps.h jeeps/gpsport.h \ + jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \ + jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \ + jeeps/gpsnmea.h jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h \ + jeeps/gpsproj.h jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h +util.o: util.c defs.h queue.h +util_crc.o: util_crc.c +vecs.o: vecs.c defs.h queue.h csv_util.h +vmem.o: vmem.c defs.h queue.h +waypt.o: waypt.c defs.h queue.h +xcsv.o: xcsv.c defs.h queue.h csv_util.h +coldsync/pdb.o: coldsync/pdb.c coldsync/config.h coldsync/palm.h \ + coldsync/pdb.h +coldsync/util.o: coldsync/util.c coldsync/config.h coldsync/pconn/util.h \ + coldsync/palm.h +jeeps/gpsapp.o: jeeps/gpsapp.c jeeps/gps.h defs.h queue.h jeeps/gpsport.h \ + jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \ + jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \ + jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h jeeps/gpsrqst.h \ + jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h +jeeps/gpscom.o: jeeps/gpscom.c jeeps/gps.h defs.h queue.h jeeps/gpsport.h \ + jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \ + jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \ + jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h jeeps/gpsrqst.h \ + jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h +jeeps/gpslibusb.o: jeeps/gpslibusb.c +jeeps/gpsmath.o: jeeps/gpsmath.c jeeps/gps.h defs.h queue.h \ + jeeps/gpsport.h jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h \ + jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h \ + jeeps/gpsnmeaget.h jeeps/gpsdatum.h +jeeps/gpsmem.o: jeeps/gpsmem.c jeeps/gps.h defs.h queue.h jeeps/gpsport.h \ + jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \ + jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \ + jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h jeeps/gpsrqst.h \ + jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h \ + jeeps/garminusb.h +jeeps/gpsprot.o: jeeps/gpsprot.c jeeps/gps.h defs.h queue.h \ + jeeps/gpsport.h jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h \ + jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h \ + jeeps/gpsnmeaget.h +jeeps/gpsread.o: jeeps/gpsread.c jeeps/gps.h defs.h queue.h \ + jeeps/gpsport.h jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h \ + jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h \ + jeeps/gpsnmeaget.h +jeeps/gpsrqst.o: jeeps/gpsrqst.c jeeps/gps.h defs.h queue.h \ + jeeps/gpsport.h jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h \ + jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h \ + jeeps/gpsnmeaget.h +jeeps/gpssend.o: jeeps/gpssend.c jeeps/gps.h defs.h queue.h \ + jeeps/gpsport.h jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h \ + jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h \ + jeeps/gpsnmeaget.h +jeeps/gpsserial.o: jeeps/gpsserial.c jeeps/gps.h defs.h queue.h \ + jeeps/gpsport.h jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h \ + jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h \ + jeeps/gpsnmeaget.h +jeeps/gpsusbread.o: jeeps/gpsusbread.c jeeps/gps.h defs.h queue.h \ + jeeps/gpsport.h jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h \ + jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h \ + jeeps/gpsnmeaget.h jeeps/garminusb.h +jeeps/gpsusbsend.o: jeeps/gpsusbsend.c jeeps/gps.h defs.h queue.h \ + jeeps/gpsport.h jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h \ + jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h \ + jeeps/gpsnmeaget.h jeeps/garminusb.h +jeeps/gpsusbstub.o: jeeps/gpsusbstub.c jeeps/garminusb.h +jeeps/gpsutil.o: jeeps/gpsutil.c jeeps/gps.h defs.h queue.h \ + jeeps/gpsport.h jeeps/gpsserial.h jeeps/gpssend.h jeeps/gpsread.h \ + jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \ + jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h \ + jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h \ + jeeps/gpsnmeaget.h +shapelib/dbfopen.o: shapelib/dbfopen.c shapelib/shapefil.h +shapelib/shpopen.o: shapelib/shpopen.c shapelib/shapefil.h +internal_styles.c: mkstyle.sh style/README.style style/arc.style style/csv.style style/custom.style style/dna.style style/fugawi.style style/gpsdrive.style style/gpsman.style style/mapconverter.style style/mxf.style style/nima.style style/s_and_t.style style/saplus.style style/tabsep.style style/xmap.style style/xmapwpt.style + ./mkstyle.sh > internal_styles.c || (rm -f internal_styles.c ; exit 1) diff --git a/README b/README new file mode 100644 index 000000000..bd6cf7ac5 --- /dev/null +++ b/README @@ -0,0 +1,983 @@ + +THE PROBLEM + + There are simply too many gratituosuly different file formats to + hold waypoint, track, and route information in various programs + used by computers. GPX (http://www.topografix.com/gpx.asp) + attempts to define a standard in XML to contain all the data, + but there are too many programs that don't understand it yet and + too much data that are in an alternate format. + +THE SOLUTION + + I needed to convert waypoints between a couple of formats, so I + whipped up a converter and based it on an extensible foundation + so that it was easy to add new formats. Most file formats + added so far have taken under 200 lines of reasonable ISO C so + they can be stamped out pretty trivially. Formats that are + ASCII text delimited in some fixed way can be added with no + programming at all via our 'style' mechanism. + +GETTING IT / BUILDING IT + + GPSBabel is distributed in source format that will work on about + any operating system and as ready-to-run binaries for some + operating systems, notably Windows. See the "OS-Specific notes" + at http://www.gpsbabel.org for instructions on those + binary kits. + + For operating systems where no binary is provided, you will have + to build it. The code should be compilable on any system with + ISO C89 compilers. It's been tested on UnixWare, OpenServer, + OS/X, Linux, Solaris, and a variety of processors and compilers. + + Libexpat is required for source builds. If you get errors about + expat.h being missing, you must either edit the Makefile to tell + the compiler where it is or install it in a sensible place. + Exapt can be downloaded from http://expat.sourceforge.net and is + part of Apache so it's very portable. + +THE FORMATS + + GPX + + This is the most capable and expressive of all the file formats + supplied. It is described at http://www.topografix.com/gpx.asp + and is supported by EasyGPS, ExpertGPS, and man other programs + described at http://www.topografix.com/gpx_resources.asp + + GEO + + geocaching.com spits up geocaching.loc files that are XML-ish but + not quite GPX. Becuase it's so close to GPX, this format is very + well supported. + + MAGELLAN + + Waypoint serial upload and download works reliably to the 315, 330, + Meridian, and SportTrak family. I expect it to work on any modern + Magellan unit. + + As of 08/30/02, GPSBabel can also read and write the files that + can be stuck on the SD memory cards with the Meridian models. + Simply specify a file instead of a serial port. + + Communication errors are handled robustly and verification of + data is enabled. + + Additional sub options: + baud: may be 1200, 2400, 4800, 9600, 19200, but must match receiver. + + GARMIN + + Waypoint serial upload and download works reliably under both + POSIX and Windows. I originally tested it with a Vista, a + V, and a base eTrex, all graciously provided on loan by Joe + Armstrong, but it's now regularly exercised on a 60CS (USB and + serial) and many other models. The communications library used, + jeeps, claims to support most models of Garmin hardware. Be + sure the GPS is set for "Garmin mode" in setup and that nothing + else (PDA hotsync programs, gpsd, getty, pppd, etc.) is using + the serial port. + + New in GPSBabel 1.2.4 is USB support, but only under Windows. + It's reported successful with VistaC, SummitC, 60C, 60CS, 76C, + 76CS, and 96C. Some users report success with StreetPilot 2610 + and some do not, but nobody's followed up with details on that. + + Quest is known to not work, not becuase of USB problems, but + rather becuase it only implements a new waypoint protocol that's + seemingly only available on that model. If you have a Quest and + would like to see it supported and can provide patches or a loan + of the equipment for a few days, please contact Robert Lipe. + + Currently, only a single USB unit at a time can be supported. The + device name to use on the command line is "usb:" Thus, to read + the waypoints from a Garmin USB unit and write them to a GPX file: + + gpsbabel -i garmin -f usb: -o gpx -F blah.gpx + + When reporting problems with Garmin, be sure to include the full + unit model, firmware version, and be prepared to offer debugging + dumps by adding "-D9" to the command line, like: + + gpsbabel -D9 -i garmin -f usb: -o gpx -F blah.gpx + + + + GPSMAN + + GPS Manager can read and write formats that this converter doesn't + understand. The default formats (WGS84, DDD) work reliably. + + GPSUTIL + + GPSUtil has a simple file format of this program that + runs on POSIX- compliant OSes like UNIX and Linux. + Reads and writes of this format are reliable. (I've + also contributed to this program.) It's available at + http://www.cs.uakron.edu/~hennings/gpsutil/. + + TIGER + + The U.S. Census Bureau proives online mapping facilities. This + format is described at: http://tiger.census.gov/instruct.html. + Do notice that this format is not the actual Tiger line mapping + records, but rather the interface to their online mapping program. + + CSV + + There are a billion variants of Comma Separated Value data. This + is the one that makes Delorme S&A Deluxe 9 happy. It's also a very + simple program and useful for many other programs like spreadsheets. + + CSV is also the correct format for Lowrance MapCreate, their + commercial mapping program, or GDM6 (their free waypoint + manager) for iFinder which is available at + http://www.lowrance.com/Software/GDM6/Default.asp + + XMap + + Delorme TopoUSA/XMap Conduit is one of the billion CSV variants + mentioned above. It's just like S&A with the addition of a + completely pointless line at the beginning and end of the file. + This is the format used to hot-sync to XMap from withing TopoUSA. + Done with help of Dan Edwards. + + XMapWpt + + Delorme XMapHandHeld Street Atlas USA is another of the billion + CSV variants. This is the format used by XmapHH SA USA on + (at least) PocketPC O/S. Please see README.xmapwpt for more + information on it's intricacies. This XMap is not to be confused + with the XMap mentioned above. Contributed to GPSBabel by + Alex Mottram. + + XCSV + + XCSV is an open-ended "Whatever Separated Values" parser / writer + designed to work with user-supplied "style" files. It should handle + at least a few thousand of the billion CSV variants available. + By itself, it doesn't comply to any format, however *most* CSV + variants can be described as a "style" and fine-tuned by the end + user. For more information on it's use, please see README.style + in the style/ sub-directory of GPSBabel. For an example of using + the XCSV module within your C program, look at the ozi.c, mxf.c, and + xmapwpt.c sources in the GPSBabel directory. This module was + contributed to GPSBabel by Alex Mottram. + + Additional Options: + style - **REQUIRED** Path to XCSV style file. + + snlen - Maximum length of synthesized shortnames. + snwhite - Switch defining whether or not to allow whitespace + in synthesized shortnames. + (0 = NO WHITESPACE, 1 = WHITESPACE OK). + snupper - Switch defining whether or not to force uppercase + in shortnames. (0 = LEAVE AS IS, 1 = UPPERCASE ALL). + + NOTE: sn* options require use of the '-s' command line option. + + Example Usage: + gpsbabel -i xcsv,style=foo.style -f foo -o xcsv,style=bar.style -F bar + gpsbabel -s -i gpx -f foo.gpx -o xcsv,style=my.style,snlen=8 -F bar + + MAPSEND + + Magellan was smart enough to document their file format to make + creating software like this possible. + + MAPSOURCE + + Garmin Mapsource format appears compatible with the various + members of that product family. Icon mapping is attempted + between different MapSource versions. Altitude is supported, + but proximity and depth are not. Naming files *.mps will + allow file->open in Mapsource to find the files more easily. + Versions 3, 4 and 5 of the Mapsource data format are handled + automatically on input and by default the output is version 5. + (Until 3/2004, it was version 3, but since Mapsource updates + are free, the convenience of having modern icon sets outweighs + the backward compatibility concern. Users of other versions + can either upgrade or specify the switches to get get output in + a compatible format.) Waypoints, routes and tracklogs are all + handled, but maps sets are ignored. + + Information on the Garmin Mapsource format was provided by Ian + Cowley and Mark Bradley. The code was implemented by Robert Lipe + and Mark Bradley. + + Additional options: + snlen - set the length of generated shortnames + mpsverout - set the data format version of the output file + (3,4 or 5) + mpsmergeout - if the output file already exists, then the output + is merged with it. This allows MapSource sections + not being handled to remain intact (e.g. map sets) + + PsiTrex + + This is a text format created by KuDaTa's PsiTrex program for + the Psion PDAs. The format can't be readily handled by XCSV, so + this format is handled explicitly. Waypoints, routes and tracks + are all handled, with icon names used corresponding to verison + 1.13 of PsiTrex. This module was contributed to GPSBabel by Mark + Bradley. + + PCX + + Garmin documents only PCX5, an older format limited to the + lame NMEA six-character waypoint names that's treated as a + second-class citizien in current versions of MapSource. In + Mapsource, use file->import to read these files. If you name + the files *.wpt, Mapsource will find them easier. + + In general, you should prefer the "mapsource" file format to + this one. + + CETUS + + Cetus GPS (http://www.cetusgps.dk/) is a program for Palm/OS. + Working with Ron Parker and Kjeld Jensen, we can now read and write + files for that program. + + QUOVADIS + + QuoVadis for Palm OS (http://www.marcosoft.com/) is a program + for Palm/OS. Working with record definitions provided by + MarcoSoft and further experimentation by Bruce Thompson and + "Fuzzy" from the Geocaching Forums to nail down the format + precisely. + + Should work fine for import and export. + + One thing of note, QuoVadis stores all waypoints in a single + Palm Database without using categories. This means that it may + be difficult to keep personal waypoints separate from + generated waypoints. What Bruce recommends is taking the + QuoVadisMarkerDB.PDB file synced down from your Palm Powered + device and extract the waypoints you personally set to a GPX + file. Then using GPSBabel's joining capabilities generate a + new PDB file from the personal file and the other waypoint + files of interest. + + Currently the selection of icons to display and the scale at + which to display them is hardcoded. Also there is no support + for notes associated with waypoints. This will be addressed in + a future revision. + + GPSPILOT + + The file format for GPSPILOT (http://www.gpspilot.com) was provided + by Ron Parker. The output from this module has been tested with + GPSPilot Tracker v5.05sx, but it is based on reverse-engineering + so it may not work with all versions of all GPSPilot products. + It had read-only support for Airport, Navaid, City and Landmark + files but will read and write Point files. + + MAGNAV + + Magellan NAV Companion for Palm/OS is not really designed for this + sort of use, but its file format is supported and with a little bit + of patience you can both read and write NAV Companion waypoints. + Please read README.magnav for further tips on getting waypoints + in and out of NAV Companion. This conversion is based on partially + incomplete reverse-engineering of the record format, so it may not + work with all versions of NAV Companion. It has been tested with + version 2.10 and 3.20. + + PSP + + Microsoft's PocketStreets 2002 Pushpin (.PSP) format is not yet + completely documented. THE .PSP MODULE DOES NOT WORK WITH MS + STREETS & TRIPS 2002 .EST FILES. To create .PSP files from + Streets & Trips 2002, you will need to have PocketStreets support + installed. Please note that MS Streets & Trips only *EXPORTS* + .PSP files. It does not import them. MS Streets & Trips 2002 + only imports CSV files. To use .PSP files, simply copy them + over to the same folder on the mobile device as the map (.MPS), + and open PocketStreets. It should also be noted that in the case + a pushpin is outside of the exported map area, the pin will be + "grayed-out" and unused in PocketStreets. This is a good thing + as it allows us to create one big .PSP file that covers multiple + .MPS files. Unfortunately, you need one .PSP file for every + .MPS file. :( + + MXF + + Maptech Exchange Format - Another CSV format file. This format + complies with (at least) Maptech Terrain Navigator, Terrain + Professional, Take a Hike, and ExpertGPS import/export MFX. + Contributed by Alex Mottram. + + DNA + + Navitrak DNA marker format - Another CSV format file. + This is the format that is compatible with the DNA Desktop + import/export command. Reading the binary Markers.jwp + format directly off the data card is not supported yet. + Contributed by Tim Zickus. + + OZI + + OziExplorer Waypoint Format - Another CSV format file. Tested + against OziExplorer v 3.90.3a / Shareware. Contributed by Alex + Mottram. + + TPG + + National Geographic Topo! Waypoint Format. This filter + reads and writes .TPG files created by various editions of NG Topo! + This filter will *not* work with the newer combined .TPO files. + Contributed by Alex Mottram. + + HOLUX + + The Holuxgm-100 (e-fox) gps receiver uses standard compact + flash cards. File formats were provided by Holux-Taiwan + http://www.holux.com.tw to the author. The code was tested + against version 2.27E1; other versions and receivers may + work but have not been explictly tested. Anyone with + information on other Holux receivers is encouraged to contact + jochen@bauerbahn.net. + + When copying the .wpo file to a flash card, the file must be + named "tempwprt.wpo" as the receiver will ignore all other + files. + + Comparing the waypoints of a .wpo files against other formats + like .gpx you may notice a small difference in the latitude + and longitude values. The reason is the low resolution of + the coordinates in the wpo file format. In a .wpo file the + reolution is 1/10"; in gpx for example it is 1/100". A a practical + matter, this loss is only about 1.7meters (5 feet). + + + The generated waypoint failes can also be used by MapShow + version 1.14. This program is free of charge from the Holux web + site. + + This format was contributed by Jochen Becker. + + TMPRO + + TopoMapPro Places File. Reads and writes places files for use + in TopoMapPro (http://www.topomappro.com). As this file type + can store links other than web links, anything that is not a + http url will be discarded. Note that this does not do datum + conversions, so if your input file does not have WGS84/NZGD2000 + data, your output file won't either. + Colour of waypoint icons defaults to red. + + GPSDRIVE + + GpsDrive way.txt file format. A space seperated format file. Tested + against GpsDrive v 1.30 found @ http://www.kraftvoll.at/software. + Contributed by Alan Curry. + + Geocaching DB + + This is a PDA file format. It was tested against version 2 + of GeocachingDB and a development snapshot of version 3. + Information on the file format came from Dougs Brat and Ron Parker. + A particularly handy way to use GPSBabel on these files is to use + GPSBabel to read a GPX file with Groundspeak (geocaching.com) + extensions and let it write you a GeocachingDB file that contains + the cache names, difficulty, terrain, and such. + + http://vip.hyperusa.com/~dougs/geocachingdb/geocachingdb.htm + + CoPilot + + This code is mostly intended to convert CoPilot Flight Planner + for Palmd/OS atabases into other formats. You probably should + not use this to write CoPilot databases, although the code is + there, because GPSBabel doesn't convert magnetic declination + values. + + Questions, bug reports, etc, to ptomblin at xcski.com + + + http://xcski.com/~ptomblin/CoPilot/ + http://navaid.com/CoPilot/ + + EasyGPS + + This is the binary file format used by EasyGPS. This format is + seemingly being phased out in favor of GPX in newer versions of + EasyGPS, but this allows conversions to and from the old binary + .loc format. + + http://www.easygps.com/ + + Information about and sketchy code to implement this file format + were provided by Eric Cloninger. + + GpilotS + + This is a Palm/OS file format ofr GPilotS. It was tested against + version 6.2. + + http://www.cru.fr/perso/cc/GPilotS/ + + Neither tracks nor routes are supported at this time. + + s_and_t + + This is a CSV format for Microsoft Streets and Trips. Detailed + instructions on how to import to it, preserving hyperlinks, are at + + http://www.gpsbabel.org/formats/s_and_t/Importing_into_Microsoft_Streets_and_Trips_2003.html + + Gcdb + + This is the GeocachingDB by DougsBrat. It works with v2 and v3 + of this program. + + http://vip.hyperusa.com/~dougs/geocachingdb/geocachingdb.htm + + NIMA + + This is a CSV format from the National Imagery and Mapping Agency. + + Fugawi + + This was a requested CSV format. It's unknown which version of + which software it works with. + + http://www.fugawi.com/ + + custom + + This is a "kitchen sink" CSV format. No known program will + read it, but it's handy for simply converting an arbitrary file + to text so it can be pulled into a spreadsheet or manipulated + with text processing tools. + + tabsep + + Dumps all fields in a traditional Unix tab separated style. + + mapconverter + + Mapconverter is a format this is read by Mapopolis.com's mapconverter + application. Full details of it's usage are available in the file + README.mapconverter. + + navicache + + This is the XML format that's used by Navicache.com for their + geocaching data. There are a number of fields in it that are + marked "required" but are Navicache-specific, so GPSBabel can not + write these files, but we can still read them. + + http://www.navicache.com/cgi-bin/ib312a/ikonboard.cgi?act=ST;f=23;t=334 + + PsiTrex + + This is a text format created by KuDaTa's PsiTrex program for the Psion + PDAs. The format can't be readily handled by XCSV, so this format is + handled explicitly. Waypoints, routes and tracks are all handled, with + icon names used corresponding to verison 1.13 of PsiTrex. + + geoniche + + Geoniche is a Palm/OS application oriented for the off-road user. + This module was contributed by Rick Richardson. + + http://www.nwlink.com/~raydar/GeoNiche/ + + gpl + + This is the 'gpl' format as used in Delorme mapping products. + It is a track format and contains little more than the tracklog + of a GPS that was attached while driving. + + http://www.frontiernet.net/~werner/gps/ + + saroute + + This is a catch-all used by many Delorme mapping products and + reads the anr, rte, and rtd formats as either tracks or routes. + + The 'turns_only' option causes GPSBabel to read only the waypoints + associated with named turns. This should create a list of waypoints + that correspond to the itinerary from Street Atlas. + + The 'turns_important' option only makes sense in conjunction with + the 'simplify' filter. It ensures that the route simplification + process will remove the points corresponding to turns only after + it has removed all other route points. + + Both options only apply to route files from newer versions of + DeLorme software; older versions didn't store the turn information + with the route. + + saplus + + This format is for Street Atlas USA 2004 Plus. + + For geocachers importing data from a tool like GSAK or Spinner, + import the file twice in XData. One will create a file with the + Cache description as a hyperlink on the flag. This can clutter + up the screen and when you try to zoom in, it causes problems. + So the second one will only have a flag. Thus you can turn off + and on which one you want to view. The first time you import + the file, in the assign field types, check the circle above Full + Name and then next. The second time you import the file do not + check any circle and in the second to last column, change URL to + none and then click next. Use the same name you used the first + time but add -Flag to it. + + nmea + + This format is the file representation of the NMEA0183 log and + waypoint format. Representative programs include: + + http://www.genimap.fi/kuluttajatuotteet/alue2.asp?folder=38&subfolder=16662&2057 + + http://homepages.tig.com.au/~robk/datalogger.html + http://www.gpstm.com/eng/features_eng.htm + http://www.gpsmaster.nl/ + http://www.silcom.com/~rwhately/index.html + http://www.visualgps.net/VisualGPSce/default.htm + http://www.gpsu.co.uk/ + http://www.kolumbus.fi/eino.uikkanen/geoconvgb/index.htm + http://www.commlinx.com.au/GPS_recorder.htm + + TEXT + + This is a simple human readable version of the data file, handy for + listings of any type of waypoint files. Use the 'nosep' option + to suppress the lines of dashes between entries. Use the + 'encrypt' option to encrypt hints from Groundspeak GPX files. + Use the 'logs' option to include Groundspeak cache logs. + + The following command line reads a GPX file with Groundspeak extensions + and writes a text file with encrypted hints: + + gpsbabel -i gpx -f 12345.gpx -o text,encrypt -F 12345.txt + + HTML + + HTML output generates a single HTML file of all of the waypoints in + the input file. It supports a number of Geocaching GPX extensions, + as well as filters out potentially harmful HTML from the input file + while maintaining almost all of the source HTML formatting. Use the + 'stylesheet' option to specify a CSS stylesheet to be used with the + resulting HTML file. Use the 'encrypt' option to encrypt hints from + Groundspeak GPX files. Use the 'logs' option to include Groundspeak + cache logs. + + The following command line reads a GPX file with Groundspeak extensions + and writes an HTML file with encrypted hints that is rendered using a + custom stylesheet: + + gpsbabel -i gpx -f 12345.gpx \ + -o html,stylesheet=green.css,encrypt -F 12345.html + + PALMDOC + + PalmDoc output is similar to Text output, except that it generates + a Palm Database (PDB) file suitable for use with programs like + CSpotRun, TealDoc, AportisDoc, Palm Reader, and others. The resulting + file also contains bookmarks to make it easy to jump to a particular + waypoint. To suppress the dashed lines between waypoints, use the + 'nosep' option. To specify a name for the document, use the 'dbname' + option. Use the 'encrypt' option to encrypt hints from Groundspeak + GPX files. Use the 'logs' option to include Groundspeak cache logs. + If you would like the generated bookmarks to start with the short name + for the waypoint, specify the 'bookmarks_short' option. This is + particularly useful when used in combination with the 'sort' filter. + + The following command line reads a GPX file with Groundspeak extensions + and writes a Palm document with encrypted hints and logs: + + gpsbabel -i gpx -f 12345.gpx \ + -o "palmdoc,dbname=Unfound Geocaches,encrypt,logs" \ + -F 12345.pdb + + Netstumbler + + NetStumbler 0.4 Summary File -- Another CSV format file. The + default behavior when creating waypoints is to use the SSID for + the short name, and information about the access point for the + description. When the SSID is not unique, is not available, or + consists of whitespace, a shortname is synthesized. The snmac + option uses the MAC address for the shortname, and includes + the unmodified SSID in the description. Different icons are + assigned to encrypted, non-encrypted, stealth, and non-stealth + access points; these may be changed with options. Import only. + + Additional options: + + nseicon - Name of icon used for non-stealth encrypted access points + + nsneicon - Name of icon used for non-stealth non-encrypted access + points + + seicon - Name of icon used for stealth encrypted access points + + sneicon - Name of icon used for stealth non-encrypted access points + + snmac - Always use the MAC address as the shortname. + + IGC + + FAI/IGC Data File -- Used by the international gliding community to + record gliding flights. IGC files can be converted to and from tracks + representing recorded flights, and routes representing task + declarations in other formats. + + BAROIQ + + Serial download protocol for the Brauniger IQ series of barograph + recording flight instruments. Creates a track of altitude vs time + which can be merged with a GPS track of the same flight to create a + three dimensional IGC file. + + hsandv + + HSA Systems Endeavour Navigator format - will import both the old + version 4.x binary files, and the newer XML based ones. + Only writes the new XML (5.0 and above) format. (use the .exp extension) + +DATA FILTERS + + GPSBabel supports data filtering. Data filters are invoked from + the command line via the '-x' option. It should be noted that + data filters are invoked in the order they appear on the command + line and can be used in intermittently between several variations + of input and output functions. It should also be noted that + filtering data from different input types can sometimes produce + undesirable results due to differences in the native data formats. + + + POSITION + + The position filter is designed to remove points based on their + proximity to each other. Distances can be passed on the command + line by passing the distance=XXX option to the filter. Distance + options may be expressed in feet (distance=3f) or meters + (distance=1m). The default is zero feet, essentially a duplicate + position. + + For example: + + gpsbabel -i geo -f 1.loc -f 2.loc -x position,distance=1f \ + -o mapsend -F 3.wpt + + would remove multiple points that are within 1 foot of each other, + leaving just one. + + You can also specify the "all" option, which would remove all + of the points rather than leaving one. + + RADIUS + + The radius filter is designed to include points based on their + proximity to a central point. Distances and the central point + are declared on the command line by passing the distance=X.XX, + lat=X.XX, and lon=X.XX options to the filter. Distance options + may be expressed in miles (distance=3M) or kilometers (distance=3K). + The default is zero miles. Additionally, the exclude option may + be specified to reverse the effect of the filter, so that points + further from the center are kept and closer points are discarded. + + For example: + + gpsbabel -i geo -f 1.loc -x radius,distance=1.5M,lat=30.0,lon=-90.0 \ + -o mapsend -F 2.wpt + + would include only points within 1.5 miles of N30.000 W90.000 + + + DUPLICATE + + The duplicate filter is designed to remove duplicate points based + on their shortname (traditionally a waypoint's name on the GPS + receiver), and/or their location (to a precision of 6 decimals). + This filter supports two options that specify how duplicates will + be recognized, "shortname" and "location". Generally, at least one + of these options is REQUIRED. For example: + + gpsbabel -i gpx -f 1.gpx -f 2.gpx -x duplicate,location,shortname \ + -o gpx -F merged_with_no_dupes.gpx + + would remove points that have duplicate shortnames *AND* duplicate + locations. The result would be a GPX file that more than likely + contains only unique points and point data. + + The duplicate filter can also take an "all" option. If you specify + that option, all instances of a duplicated waypoint will be removed, + not just the second and subsequent instances. If your input file + contains waypoints A, B, B, and C, the output file will contain + waypoints A, B, and C without the "all" option, or just A and C + with the "all" option. This option can be useful as an "ignore + list" in some circumstances. + + Finally, the duplicate filter takes a "correct" option. If you + specify that option, the latitude and longitude frmo later duplicates + will replace the latitude and longitude in earlier waypoints. You + can use this to apply a list of "waypoint corrections" to a larger + file, while keeping all of the other details from the larger file. + + DISTANCE FROM A ROUTE (ARC) + ARC + + The arc filter is designed to include points based on their + proximity to an arc, which is a series of connected line + segments similar to a route or a track but without any + associated data other than the coordinates. + + The arc is defined in a file whose name must be provided with + the file=XXXX option to the filter. That file contains pairs + of coordinates for the vertices of the arc, one coordinate pair + per line. Comments may be included by preceding them with a '#' + character. An arc file looks something like this sample: + + # Lima Road/SR3 north of Fort Wayne, Indiana + 41.150064468 -85.166207433 + 41.150064468 -85.165371895 + 41.149034500 -85.165157318 + 41.147832870 -85.164771080 + 41.146631241 -85.164384842 + 41.144270897 -85.163655281 + 41.141953468 -85.162882805 + + In addition to the file containing the arc, you should also + specify the maximum distance from the arc that will be accepted; + that distance is declared on the command line with the + distance=X.XX option to the filter. Distance options may be + expressed in miles (distance=3M) or kilometers (distance=3K). + The default is zero miles. You may also specify the exclude option, + which causes GPSBabel to only include points that are further than + the specified distance from the arc. + + For example, assuming the arc above is in a file called "lima_rd.txt": + + gpsbabel -i geo -f 1.loc -x arc,file=lima_rd.txt,distance=1 \ + -o mapsend -F 2.wpt + + would include only points within one mile of the section of Lima Road + covered by the arc. + + POLYGON + + The polygon filter includes points if they are inside of a polygon. + A polygon file looks like an arc file, except that the arc it + describes must be a closed cycle. That is, for a simple polygon, + the first and last points must be the same. Here's a square: + + # A square (not really) polygon + 41.0000 -85.0000 + 41.0000 -86.0000 + 42.0000 -86.0000 + 42.0000 -85.0000 + 41.0000 -85.0000 + + Polygons may include islands and holes. To specify an island or a + hole, just append it to the main polygon. + + As with the arc filter, you specify a polygon by specifying the name + of the polygon that contains it, using the file option. You can also + specify the exclude option, which reverses the operation of the filter + so that it only includes points that are NOT in the polygon. + + Note that this filter currently will not work properly if your polygon + contains one or both poles or if it spans the line of 180 degrees + east or west longitude. + + For example, assume you have a polygon file that defines the border of + your county, called mycounty.txt. This command line will give you only + the points in your county: + + gpsbabel -i geo -f 1.loc -x polygon,file=mycounty.txt \ + -o mapsend -F 2.wpt + + SIMPLIFY + + The Simplify filter is used to simplify routes and tracks for use + with formats that limit the number of points they can contain. + The filter takes one required parameter, which is the maximum + number of points a route may contain. It attempts to remove + points from each route until the number of points is at or below + the given maximum, while also attempting to preserve the shape of + the original route as much as possible. + + The quality of the results will vary depending on the density of + points in the original route and the length of the original route. + + For example, suppose you have a route from Street Atlas 2003 that + you wish to use with a Magellan GPS receiver that only supports up + to 50 points in a route: + + gpsbabel -r -i saroute -f RoadTrip.anr -x simplify,count=50 \ + -o magellan -F grocery.rte + + REVERSE + + The reverse filter is used to reverse tracks and routes. It's + mostly useful for those few formats where track/route sequence matters + and there isn't a way to reverse them using the program itself. + + The reversal is performed in the laziest way possible. + Timestamps are kept with the original waypoints so the resulting + track or route will have the interesting characteristic that + time runs backwards. This tends to make Magellan Mapsend, + in particular, do a wierd thing and place each waypoint on a + separate day. + + Additionally, if you're using this to reverse a route that + navigates, say, an exit ramp or a one way street, you will be in + for unpleasant ride. application cares about timestamps + + SORT + + This simple filter allows you to alphabetize waypoints by + shortname or by description. It has a special suboption (gcid) + to sort by geocaching.com waypoint ID's when the input comes + from a GPX file that has GC numbers in it. + + STACK + + This filter is designed to solve advanced problems that involve + shuffling multiple lists of waypoints. It has three distinct + sets of suboptions: + + PUSH + + Pushes the current list of waypoints onto the stack. If + the 'copy' suboption is specified, a copy of the current + list is pushed onto the stack; otherwise, the current + list is cleared. + -x stack,push + -x stack,push,copy + + POP + + 'Pops' the top list of waypoints off of the stack. What is + done with that list depends on the suboption specified. If + the 'append' suboption is specified, the top list of waypoints + from the stack is added to the end of the current list of + waypoints. If the 'discard' option is specified, the top + list of waypoints is removed from the stack and discarded, + leaving the current list of waypoints unchanged. If the + 'replace' option is specified, or if no option is specified, + the top list of waypoints from the stack replaces the current + list of waypoints; the previous contents of the current list + are discarded. + -x stack,pop + -x stack,pop,discard + -x stack,pop,append + + SWAP + + Swaps the current list of waypoints with a list from the + stack. If no further options are specified, the current + list is swapped with the top list on the stack. If the + 'depth' option is specified, it indicates which item on + the stack should be swapped. + -x stack,swap + -x stack,swap,depth=2 + + The stack can be used in conjunction with other filters to + implement a "union" or "logical or" functionality. The basic + idea is to use the stack to store copies of the original list + of waypoints, then use the 'swap' function to replace each copy + with a filtered list. Finally, append all of the filtered lists + to create one big list, which is then output. The following + example finds a list of all points that are either inside county A + or inside county B. Any points that are inside both counties are + duplicated (but the duplicates can be removed with the DUPLICATE + filter; see above.) + + gpsbabel -i gpx -f in.gpx \ + -x stack,push,copy \ + -x polygon,file=county_a.txt \ + -x stack,swap \ + -x polygon,file=county_b.txt \ + -x stack,pop,append \ + -o gpx -F out.gpx + + This example reads a large list of waypoints and extracts the + points within 20 miles of each of two cities, writing the + waypoint descriptions into two different PalmDoc files and + exporting all of the points to the GPS receiver: + + gpsbabel -i gpx -f indiana.gpx \ + -x stack,push,copy \ + -x radius,lat=41.0765,lon=-85.1365,distance=20m \ + -o palmdoc,dbname=Fort\ Wayne -F fortwayne.pdb \ + -x stack,swap \ + -x radius,lat=39.7733,lon=-86.1433,distance=20m \ + -o palmdoc,dbname=Indianapolis -F indianapolis.pdb \ + -x stack,pop,append \ + -o magellan -F fwaind.wpt + +COMMON USAGE + + Invocation was meant to be flexible. Unfortunately, that can + sometimes lead to unwieldy command lines. + + gpsbabel -? + + will always show you the supported file types. To use this + program, just tell it what you're reading, where to read it from, + what you're writing, and what to write it to. For example: + + gpsbabel -i geo -f /tmp/geocaching.loc -o gpx -F /tmp/geocaching.gpx + + tells it to read the first file in geocaching.com format and create + a new file in GPX format. + + This command will read from a Magellan unit attached to the first + serial port on a Linux system (device names will vary on other OSes) + and write them as a geocaching loc file. The second command does + the same for windows. + + gpsbabel -i magellan -f /dev/ttyS0 -o geo -F mag.loc + gpsbabel -i magellan -f com1 -o geo -F mag.loc + + + Optionally, you may specify "-s" in any command line. This causes + the program to ignore any "short" names that may be present in the + source data format and synthesize one from the long name. This + is particularly useful if you're writing to a target format that + isn't the lowest common denominator but the source data was written + for the lowest common denominator. I use this for writing data + from geocaching.com to my Magellan so my waypoints have "real" names + instead of the 'GC1234' ones that are optimized for NMEA-only + receivers. A geocacher with a Magellan receiver may thus find + commands like this useful. + + gpsbabel -s -i geo -f geocaching.loc -o magellan -F /dev/ttyS0 + gpsbabel -s -i geo -f geocaching.loc -o magellan -F com1 + +ADVANCED USAGE + + Argument are processed in the order they appear on the command line. + Input is cumulative. The input file type remains unchanged until a + new -i argument is seen. Files are read in the order they appear. + So you could merge three input files into one output file with: + + gpsbabel -i geo -f 1.loc -f 2.loc -f 3.loc -o geo -F big.loc + + You can merge files of different types: + + gpsbabel -i geo -f 1.loc -i gpx -f 2.gpx -i pcx 3.pcx -o gpsutil -F big.gps + + You can write the same data in different output formats: + + gpsbabel -i geo -f 1.loc -o gpx -F 1.gpx -o pcx 1.wpt + +ROUTE AND TRACK MODES + + The presence of "-t" on the command line tells us to work with + tracks. The presence of "-r" tells us to work with routes. + Tracks and routes are advanced features and don't try to + handle every possible hazard that can be encountered during a + conversion. If you're merging or converting files of similar + limitations, things work very well. The presence of "-s" on + the command line tends to creat havoc because tracks and routes. + diff --git a/README.contrib b/README.contrib new file mode 100644 index 000000000..baa8579ff --- /dev/null +++ b/README.contrib @@ -0,0 +1,40 @@ +If you're interested in contributing to this program, here are some +guidelines. Mail patches to gpsbabel-code@lists.sourceforge.net for +consideration and integration. + +Standards are good. ISO C and POSIX are greatly preferred. + +Reuse is good, if doing so is not onerous. For example, using the expat +libraries vastly simplifies the XML parsers while increasing their +robustness plus those libraries are ubiquitous. So I consider it OK to +require expat. + +If you are creating a new target you should submit patches (use +"cvs diff -uN" to create patches) to the following files: +* Yourcode.c and/or Yourcode.h - this is the code required to do your + conversions and any support files that your code requires. +* vecs.c - an updated vecs.c file implementing your conversion code into + GPSBabel. +* Makefile - an updated Makefile telling the compiler how to build and link + your conversion into GPSBabel +* README - an excerpt for the README about your conversion and any + idiosyncrasies it may have. +* testo - an updated script that tests your conversion (this should produce + no output if all is good, see the current testo script for examples) +* YourOutput - a sample file of code produced by your function (used in testo + and lives in a directory called "reference"). + +Please ensure that you are building and testing against the latest code +from the top of the CVS tree and that any code you modify is the latest +version from the CVS - Note: code changes sometimes occur frequently! + +Compilers complain for a reason. Code shouldn't emit warnings. + +The entire world doesn't run . I've tested this code on +at least five different OSes. If you find yourself wanting to insert +compiler or OS specific magic, please resist. + +Enjoy! + +Robert Lipe, +robertlipe@usa.net diff --git a/README.igc b/README.igc new file mode 100644 index 000000000..af057a340 --- /dev/null +++ b/README.igc @@ -0,0 +1,127 @@ +IGC Data Format Notes. +====================== +Refer to Appendix 1 of http://www.fai.org:81/gliding/gnss/tech_spec_gnss.asp +for the specification of the IGC data format. + +A sample list of software applications that use data in IGC format can be +found at http://www.fai.org:81/gliding/gnss/gnss_analysis_software.pdf + +GPSBabel can be used to translate data in IGC format to and from various other +formats. + +Routes in other formats are used to represent IGC task declarations. +Tracks in other formats are used to represent IGC recorded flights. + + + +Converting to IGC format +======================== +IGC files generated by GPSBabel will NOT pass security validation tests since +the data they contain cannot be proven to originate from an approved flight +recorder. For most software applications that use IGC files this is not an +issue but for competition scoring, record and badge claims the generated files +will not be accepted as proof of a flight. + +A track stored in another format (GPX for example) representing a recorded +flight can be converted into an IGC file: + + gpsbabel -i gpx -f mytrk.gpx -o igc -F myflight.igc + +If multiple track segments are provided in the input file, the one with the +most points will be used. + +A route stored in another format representing a task declaration can be +converted into an IGC file: + + gpsbabel -i gpx -f myrte.gpx -o igc -F mytask.igc + +A route and a track in other formats can be included into a single IGC file: + + gpsbabel -i gpx -f mytrk.gpx -f myrte.gpx -o igc -F myflight.igc + +A similar result can be obtained by downloading the track log and routes +directly from a GPS device connected to a PC. For example to create an IGC +file from data recorded in a Garmin GPS connected to the first serial port of +a PC running Linux: + + gpsbabel -t -r -i garmin -f /dev/ttyS0 -o igc -F myflight.igc + +For Windows operating systems: + + gpsbabel -t -r -i garmin -f com1 -o igc -F myflight.igc + +A waypoint file in another format containing a waypoint whose short name is +"PILOT" can be merged into an IGC file. The description field of the waypoint +will be used for the pilot name in the IGC file header: + + gpsbabel -i gpx -f mytrk.gpx -f myrte.gpx -f mywpt.gpx -o igc -F myflight.igc + gpsbabel -w -t -r -i garmin -f /dev/ttyS0 -o igc -F myflight.igc + +Some formats such as GPX allow routes, tracks and waypoints to exist in the +same file and can be used to fully populate an IGC file: + + gpsbabel -i gpx -f myall.gpx -o igc -F myflight.igc + + + +Converting from IGC format +========================== +Data in an IGC file can be converted into other formats. For example to +generate OziExplorer files containing tracks representing the recorded +flight (myozi.plt) and routes representing declared tasks (myozi.rte): + + gpsbabel -i igc -f myflight.igc -o ozi -F myozi + +Or to GPX format: + + gpsbabel -i igc -f myflight.igc -o gpx -F myflight.gpx + +Header information from the IGC file will be written to the description field +of the track(s). + +If both pressure altitude and GNSS altitude are recorded in the IGC file, two +tracks will be written to the new track file, representing the two altitude +tracks. The latitude, longitude and timestamps in the tracks will be identical. + + +Merging into IGC format +======================= +A route stored in another format can be merged with an existing IGC file that +has no task declaration, to generate a new IGC file with a task declaration: + + gpsbabel -i igc -f myflight.igc -i gpx -f myrte.gpx -o igc -F mynew.igc + +A two dimensional (lat/lon) track recorded during a flight by a GPS receiver +can be merged with a one dimensional (altitude) track recorded during the same +flight by a barograph instrument. The result is a three dimensional IGC file +representing the flight: + + gpsbabel -i gpx -f baro.gpx -i igc -f my2D.igc -o igc -F my3D.igc + +Sometimes there is a discrepancy between the internal clock in the barograph +instrument and GPS time which can result in the altitude and ground positions +not correlating correctly. This can be corrected manually by passing the time +difference in seconds between the two time domains through the "timeadj" +parameter. This can be any positive or negative integer: + + gpsbabel -i gpx -f baro.gpx -i igc -f my2D.igc -o igc,timeadj=27 -F my3D.igc + +GPSBabel can also attempt to deduce the time difference automatically. This +is done by comparing the time that it thinks that you landed on the GPS track +and the barograph and adjusting accordingly: + + gpsbabel -i gpx -f baro.gpx -i igc -f my2D.igc -o igc,timeadj=auto -F my3D.igc + +The same can be acheived by downloading directly from a barograph instrument +supported by GPSBabel. For example with a Brauniger IQ Comp GPS variometer: + + gpsbabel -i baroiq -f /dev/ttyS0 -i igc -f my2D.igc -o igc,timeadj=auto -F my3D.igc + +or: + + gpsbabel -i baroiq -f com1 -i igc -f my2D.igc -o igc,timeadj=auto -F my3D.igc + + + +Chris Jones +Aug 2004 diff --git a/README.magnav b/README.magnav new file mode 100644 index 000000000..c0cf42e70 --- /dev/null +++ b/README.magnav @@ -0,0 +1,28 @@ +Translating NAV Companion waypoints to another format is as easy +as with any other format. Just find the Companion_Waypoints database +in your palm backup directory and use it as the input file. + +When translating waypoints back to NAV Companion, though, you need +to jump through some hoops: + +First, you must merge any waypoints that already exist in the database +in your Palm Backup directory with the ones you are adding; failure to +do so will result in only the new points being available in NAV Companion, +even if you give the new database a different name (it will overwrite +the old database, even in your backup directory. That's a feature of +PalmOS, not of NAV Companion.) + +To merge the databases, use a command line like the following: + +gpsbabel -i magnav -f Companion_Waypoints.PDB -i geo -f geocaching.loc -o magnav -F merged.pdb + +Second, you must use the installer to install your new PDB file. Don't +make the mistake of copying it over the existing Companion_Waypoints.PDB +file; the one on the handheld will overwrite it rather than merging with +it. + +Finally, because NAV Companion is not designed to work with desktop +applications, you must tell NAV Companion that its waypoints database +has changed out from under it. One way to do this is to go to the +waypoints screen and attempt to scroll; that will force it to reread +the database and fix the record pointers that it keeps on the heap. diff --git a/README.mapconverter b/README.mapconverter new file mode 100644 index 000000000..9c0791d43 --- /dev/null +++ b/README.mapconverter @@ -0,0 +1,35 @@ +Mapconverter is an application used to create userland maps and map data for +Mapopolis.com's Mapopolis program. The mapconverter format is essentially +waypoint data prepared in a format that the mapconverter application will +accept. + +The steps for using GPSBabel and Mapconverter go something like this: + +Step 1: Create a mapconverter file using gpsbabel. + ./gpsbabel -i geo -f geocaching.loc -o mapconverter -F foo.txt + +Step 2: Launch mapconverter.exe and choose foo.txt as your input file. + Click the begin button to have mapconverter process foo.txt. + +If all goes successfully, you should have a file called "foo.pdb" ready +for syncing with your PDA. Put it wherever Mapopolis thinks it should be +on your PDA. + +NOTES: + +o GPSBabel will write the name of its own output file in the output file + it creates as the input for Mapconverter. Mapconverter will replace + the extension of this filename with ".pdb". + +o The PocketPC version of Mapopolis doesn't notice files with the ".pdb" + extension. To make this work, change the extension to ".mlp" when + copying the mapconverter output to your PocketPC PDA. + +o Mapconverter only works with Mapopolis version 3.x. Mapopolis version + 4 will refuse to load mapconverter maps. There is no known work-around + for this at the time of this writing. + +o Mapconverter is no longer available from the Mapopolis website. If you + need a copy of mapconverter, ask on your local GPS Software discussion + forum and I'm sure someone will have it. As far as I know, It was never + actually acknowledged/supported by Mapopolis to begin with. diff --git a/README.psp b/README.psp new file mode 100644 index 000000000..ab15d0969 --- /dev/null +++ b/README.psp @@ -0,0 +1,112 @@ +MS Pocketstreets 2002/2003 Pushpins (.PSP) Q & A +------------------------------------------------ + +Q: Why should I use gpsbabel/psp to make pushpins when Streets & Trips (S&T) + already does that for me? + +A: gpsbabel/psp has the advantage of being able to create pushpins WITHOUT + creating the associated map file and the need to "import" the waypoint + data into S&T. Through a series of scripts, you can create a dozen + or so PSP files in a few seconds as opposed to a few weeks using the + S&T interface. The maps are not going to change between sessions, + only the pins will. Why waste all that time creating maps when all you + really want are updated pins? As an aside, gpsbabel/psp creates points + WITH THE PROPER coordinates where S&T does not in some areas of the U.S. + (Nashville, TN for instance). + + +Q: I keep getting a blank (32 byte) PSP file? + +A: There are either no points to write, or you have botched the command + line for gpsbabel. gpsbabel is sensitive to UPPER and lower case + on the command line. A simple command line to create PSP files + looks like this: + + gpsbabel -i geo -f geocaching.loc -o psp -F NewOrleans.psp + + Note the use of "-f" for INPUT files and "-F" for OUTPUT files. + + +Q: I've created a PSP file, now what do I do with it? + +A: To use pushpins in Pocketstreets, you need to have both a map and a + pushpin file. These two files must exist in the same folder and have + exactly the same base name as the map. For example, the pins that + correspond to the map "NewOrleans.mps" should be named "NewOrleans.psp". + + +Q: I don't have a map? What do I do now? + +A: Create one using the "Export map to Pocketstreets" option in S&T. You + can also pick up some major city maps on the web from the MS Pocketstreets + website if you are interested in seeing how it works. + + +Q: I have .EST files, not .PSP files. What's up with that? + +A: In order to make PSP files, you need to use the "Export map to + Pocketstreets" function in S&T. .EST files are for use in S&T, not + Pocketstreets. + + +Q: The .PSP files differ when I use gpsbabel/psp versus Pocketstreets to + create them. What's up? + +A: Pocketstreets makes corrections to the S&T waypoint data upon initial + loading. gpsbabel/psp writes PSP files with these corrections already made. + Ask MS. + + +Q: Does gpsbabel/psp work with (Autoroute, Mappoint, etc..) .PSP files? + +A: As of this writing, I haven't seen any so I can't be sure. If they + follow the same layout as S&T 2002, I'd imagine so. + + +Q: Does gpsbabel/psp work with (S&T 2001, S&T 2002, etc...) files? + +A: MS the file layout between S&T 2001 and S&T 2002. The gpsbabel psp + module is known to work fine with S&T 2002 and 2003. + + +Q: Does gpsbabel/psp work with (insert your country/location here) maps? + +A: If it doesn't, feel free to email the PSP files to me at: + geo_alexm at cox-internet.com. I only had USA based data to work + with while figuring out the file layout. Please include as much + information about the points as possible (lat/long, name, etc..) + and do it in English. I don't read or speak any other languages + fluently. + + +Q: What do you mean S&T writes points with the wrong coordinates? + +A: At some point in the "Export map to Pocketstreets" function in S&T, + it goofs the lat/long data. Points in Nashville tended to shift + 1.4 miles WEST of their original location. I'm not a geometry buff, + but I'd imagine they have a reference point for generating coordinates + that's wrong in (at least) that area. + + +Q: I have 800 waypoints that cover a dozen or so Pocketstreets maps. + Do I need to to split my points up into smaller chunks to match the + area covered by the maps? + +A: No. Pocketstreets will "ignore" points that are outside of the map + area. Points that are not on the current map will be "grayed out" + in pushpin explorer in Pocketsreets. This is the reason the PSP + module was written for gpsbabel in the first place. + + +Q: Where can I find documentation for the layout of PSP files? + +A: Just about everything I know about the PSP file format is documented + in the source. To the best of my knowledge, there is no documentation + (and for good reason, I've come to discover). + + +Q: I have some other problem, what do I do? + +A: Email me at geo_alexm at cox-internet.com and I'll see if I can + work it out. + diff --git a/README.xmapwpt b/README.xmapwpt new file mode 100644 index 000000000..6e8539c1e --- /dev/null +++ b/README.xmapwpt @@ -0,0 +1,66 @@ + +NOTE: THIS README PERTAINS TO THE "XMAPWPT" FORMAT, NOT THE XMAP/TOPO USA + 4.0 CONDUIT "XMAP" FORMAT. + + +Delorme XMap Handheld .WPT for PocketPC is a bit of a kludge. This +document covers XMap Handheld Street Atlas USA edition. + +XMap on the PocketPC stores it's waypoints in individual .wpt files. +For example, waypoints generated by XMap on the PocketPC are stored +by default in the "My Documents" folder using the sequential names +"XMap1.wpt", "XMap2.wpt", ad nauseum. Needless to say, not very +efficient. + +As writing multiple waypoint files is outside of the scope of gpsbabel, +gpsbabel chooses to write one big file, one waypoint per line. +Extracting lines from this file is left as an exercise for the end user. +A simple perl script to handle this conversion is included at the end +of this README. + +It should also be noted that READING multiple files is indeed possible, +but if you have more than a few points, it can be a task. For example: + +gpsbabel -i xmapwpt -f Xmap1.wpt -f Xmap2.wpt -o mapsend -F mapsend.wpt + +will read the two Xmap .wpt files and write one mapsend file. This +is fine for a small handful of points, but could be quite cumbersome +for folks like me who have 100+ waypoints loaded into XMap. For *nix +folks, something as simple as: + +cat *.wpt > /tmp/foo.wpt +gpsbabel -i xmapwpt -f foo.wpt -o mapsend -F mapsend.wpt + +will do the trick just fine. + + +############ BEGIN SCRIPT +#!/full/path/to/perl +$INPUTFILE = @ARGV[0]; +$TARGETDIR = @ARGV[1]; +$FILENAME = @ARGV[2]; + +if (! $FILENAME) { + print "Usage: xmap_split.pl INPUT_FILE OUTPUT_DIRECTORY FILENAME_BASE\n"; + print " (i.e. xmapl_split.pl points.wpt /tmp/points GPSB)\n"; + print " (created GPSB0001-GPSBXXXX in /tmp/points/ from points.wpt)\n"; + exit; +} + +open (INFILE, $INPUTFILE) || die "Cannot open $INPUTFILE for read!\n"; + +while () { + $lc++; + $filename = sprintf("%s/Gpsb%04d.wpt", $TARGETDIR, $lc); + + open (OUTFILE, ">$filename") || die "Cannot open $filename for write!\n"; + + print OUTFILE $_; + + close(OUTFILE); +} + +exit; + +########### END SCRIPT + diff --git a/arcdist.c b/arcdist.c new file mode 100644 index 000000000..3fc13459a --- /dev/null +++ b/arcdist.c @@ -0,0 +1,165 @@ +/* + Distance from point to arc filter + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include +#include "defs.h" +#include "grtcirc.h" + +#define MYNAME "Arc filter" + +extern queue waypt_head; + +static double pos_dist; +static char *distopt = NULL; +static char *arcfileopt = NULL; +static char *exclopt = NULL; +static char *ptsopt = NULL; + +typedef struct { + double distance; +} extra_data; + +static +arglist_t arcdist_args[] = { + {"file", &arcfileopt, "File containing vertices of arc", + NULL, ARGTYPE_FILE | ARGTYPE_REQUIRED}, + {"distance", &distopt, "Maximum distance from arc", + NULL, ARGTYPE_FLOAT | ARGTYPE_REQUIRED}, + {"exclude", &exclopt, "Exclude points close to the arc", NULL, + ARGTYPE_BOOL}, + {"points", &ptsopt, "Use distance from vertices not lines", + NULL, ARGTYPE_BOOL}, + {0, 0, 0, 0, 0} +}; + +#define BADVAL 999999 + +void +arcdist_process(void) +{ + queue * elem, * tmp; + waypoint * waypointp; + double dist; + extra_data *ed; + double lat1, lon1, lat2, lon2; + int fileline = 0; + + FILE *arcfile = xfopen( arcfileopt, "r", MYNAME ); + + lat1 = lon1 = lat2 = lon2 = BADVAL; + while ( !feof(arcfile)) { + char line[200]; + char *pound = NULL; + int argsfound = 0; + + fgets( line, sizeof(line), arcfile ); + + fileline++; + + pound = strchr( line, '#' ); + if ( pound ) *pound = '\0'; + + lat2 = lon2 = BADVAL; + argsfound = sscanf( line, "%lf %lf", &lat2, &lon2 ); + + if ( argsfound != 2 && strspn(line, " \t\n") < strlen(line)) { + warning(MYNAME ": Warning: Arc file contains unusable vertex on line %d.\n", fileline ); + } + else if ( lat2 != BADVAL && lon2 != BADVAL && + (ptsopt || (lat1 != BADVAL && lon1 != BADVAL ))) { + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + + waypointp = (waypoint *)elem; + if ( ptsopt ) { + dist = gcdist( lat2*M_PI/180.0, lon2*M_PI/180.0, + waypointp->latitude*M_PI/180.0, + waypointp->longitude*M_PI/180.0 ); + } + else { + dist = linedist(lat1, lon1, lat2, lon2, + waypointp->latitude, + waypointp->longitude ); + } + + /* convert radians to float point statute miles */ + dist = tomiles(dist); + + if ( waypointp->extra_data ) { + ed = (extra_data *) waypointp->extra_data; + } + else { + ed = (extra_data *) xcalloc(1, sizeof(*ed)); + ed->distance = BADVAL; + } + if ( ed->distance > dist ) { + ed->distance = dist; + } + waypointp->extra_data = ed; + } + } + lat1 = lat2; + lon1 = lon2; + } + + fclose(arcfile); + + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + waypoint *wp = (waypoint *) elem; + ed = (extra_data *) wp->extra_data; + wp->extra_data = NULL; + if ( ed ) { + if ((ed->distance >= pos_dist) == (exclopt == NULL)) { + waypt_del(wp); + waypt_free(wp); + } + xfree( ed ); + } + } +} + +void +arcdist_init(const char *args) { + char *fm; + + pos_dist = 0; + + if (distopt) { + pos_dist = strtod(distopt, &fm); + + if ((*fm == 'k') || (*fm == 'K')) { + /* distance is kilometers, convert to feet */ + pos_dist *= .6214; + } + } +} + +void +arcdist_deinit(void) { + /* do nothing */ +} + +filter_vecs_t arcdist_vecs = { + arcdist_init, + arcdist_process, + arcdist_deinit, + NULL, + arcdist_args +}; diff --git a/brauniger_iq.c b/brauniger_iq.c new file mode 100644 index 000000000..2d06c5753 --- /dev/null +++ b/brauniger_iq.c @@ -0,0 +1,279 @@ +/* + * Serial download of barograph data from a Brauniger IQ Variometer. + * + * Copyright (C) 2004 Chris Jones + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111 USA + */ + +#include "defs.h" +#include "jeeps/gpsserial.h" +#include + +static int32 fd; +static char *port; + +#define MYNAME "BRAUNIGER-IQ" +#define PRESTRKNAME "PRESALTTRK" + +static enum { + st_sync, + st_fl_num, + st_data_len, + st_ser_num, + st_pilot_name, + st_start_date, + st_start_year, + st_max_alt_1, + st_max_alt_2, + st_max_climb, + st_flight_dur, + st_log_ival, + st_start_time, + st_end_time, + st_sample_alt, + st_sample_spd, + num_states +} state; + +static const int reqd_bytes[num_states] = { 6, 1, 2, 2, 25, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1 }; + +static void rd_init(const char *fname) +{ + port = xstrdup(fname); + + // Fortunately the instruments use the same serial settings as the Garmin + // GPS receivers (9600-8-N) so we can use jeeps and hence we don't need + // to worry about OS dependencies here. + if (!GPS_Serial_On(port, &fd)) { + fatal(MYNAME ": Can't initialise port '%s'\n", port); + } +} + +static void rd_deinit(void) +{ + if (!GPS_Serial_Off(port, fd)) { + fatal(MYNAME ": Can't shut down port '%s'\n", port); + } + if (!GPS_Serial_Close(fd, port)) { + fatal(MYNAME ": Can't close port '%s'\n", port); + } + xfree(port); +} + +/** + * Process a data record. + * @return zero when all expected data has been received + */ +static int process_data(const unsigned char *data) +{ + static int remaining = 100; + static struct tm tm; + static time_t start, creation; + static route_head *track; + static unsigned char interval; + time_t finish; + waypoint *wpt = NULL; + int i; + + if (global_opts.debug_level >= 3) { + for (i = 0; i < reqd_bytes[state]; i++) { + printf("%.2x ", data[i]); + } + puts(""); + } + + remaining -= reqd_bytes[state]; + switch (state) { + case st_sync: + if (memcmp(data, "\x30\x31\x32\x33\x34\x35", 6) != 0) { + fatal(MYNAME ": Could not synchronise\n"); + } + break; + + case st_fl_num: + if (global_opts.debug_level >= 1) { + printf(MYNAME ": Flight Number: %d\n", data[0]); + } + break; + + case st_data_len: + remaining = (data[0] << 8) + data[1] - 2; + if (global_opts.debug_level >= 1) { + printf(MYNAME ": Data Length: %d\n", remaining); + } + break; + + case st_ser_num: + if (global_opts.debug_level >= 1) { + printf(MYNAME ": Serial Number: %d\n", (data[0] << 8) + data[1]); + } + break; + + case st_pilot_name: + if (global_opts.debug_level >= 1) { + printf(MYNAME ": Pilot Name: %.25s\n", data); + } + break; + + case st_start_date: + i = (data[0] << 8) + data[1]; + tm.tm_mday = i / 100; + tm.tm_mon = (i % 100) - 1; + break; + + case st_start_year: + tm.tm_year = ((data[0] << 8) + data[1]) - 1900; + break; + + case st_max_alt_1: + if (global_opts.debug_level >= 1) { + printf(MYNAME ": Max Altitude 1: %dm\n", (data[0] << 8) + data[1]); + } + break; + + case st_max_alt_2: + if (global_opts.debug_level >= 1) { + printf(MYNAME ": Max Altitude 2: %dm\n", (data[0] << 8) + data[1]); + } + break; + + case st_max_climb: + if (global_opts.debug_level >= 1) { + i = (data[0] << 8) + data[1]; + printf(MYNAME ": Max climb: %d.%dm/s\n", i / 10, i % 10); + } + break; + + case st_flight_dur: + if (global_opts.debug_level >= 1) { + i = (data[0] << 8) + data[1]; + printf(MYNAME ": Flight Time: %d:%d\n", i / 100, i % 100); + } + break; + + case st_log_ival: + interval = data[0]; + if (global_opts.debug_level >= 1) { + printf(MYNAME ": Logging Interval: %ds\n", interval); + } + break; + + case st_start_time: + i = (data[0] << 8) + data[1]; + tm.tm_hour = i / 100; + tm.tm_min = (i % 100) - 1; + tm.tm_sec = 0; + creation = start = mktime(&tm); + if (global_opts.debug_level >= 1) { + printf(MYNAME ": Start Time: %s", ctime(&start)); + } + break; + + case st_end_time: + i = (data[0] << 8) + data[1]; + tm.tm_hour = i / 100; + tm.tm_min = (i % 100) - 1; + finish = mktime(&tm); + if (global_opts.debug_level >= 1) { + printf(MYNAME ": End Time: %s", ctime(&finish)); + } + if (remaining) { + track = route_head_alloc(); + track->rte_name = xstrdup(PRESTRKNAME); + track->rte_desc = xstrdup("Brauniger-IQ Barograph"); + track_add_head(track); + } else { + warning(MYNAME ": No barograph recorded for this flight\n"); + } + break; + + case st_sample_alt: + wpt = waypt_new(); + wpt->latitude = wpt->longitude = 0.0; + wpt->creation_time = creation; + creation += interval; + wpt->altitude = (data[0] << 8) + data[1]; + route_add_wpt(track, wpt); + if (global_opts.debug_level >= 2) { + printf(MYNAME ": remaining=%d, Altitude=%fm, ", remaining, wpt->altitude); + } + break; + + case st_sample_spd: + if (global_opts.debug_level >= 2) { + printf("Airspeed=%dkmh\n", data[0]); + } + state = st_sample_alt; + return remaining; + + default: + fatal(MYNAME ": Bad internal state\n"); + } + state++; + return remaining; +} + +static void data_read(void) +{ + unsigned char ibuf[25]; + int32 rd_cnt, ofs; + + if (global_opts.debug_level >= 0) { + puts(MYNAME ": Select recorded flight in memo mode."); + puts(MYNAME ": Press Memo button for two seconds..."); + } + // Wait until something arrives + while (!GPS_Serial_Wait(fd)); + if (global_opts.debug_level >= 0) { + puts(MYNAME ": Downloading flight..."); + } + // Read data until there is none left to read + state = st_sync; + ofs = 0; + do { + if (0 > (rd_cnt = GPS_Serial_Read(fd, ibuf + ofs, reqd_bytes[state] - ofs))) { + fatal(MYNAME ": Error reading port '%s', %s\n", port, strerror(errno)); + } + if (reqd_bytes[state] == rd_cnt + ofs) { + if (!process_data(ibuf)) { + if (global_opts.debug_level >= 0) { + puts(MYNAME " ...Finished"); + } + return; + } + ofs = 0; + } else { + ofs += rd_cnt; + } + } while (GPS_Serial_Wait(fd)); + fatal(MYNAME ": Incomplete download\n"); +} + +static arglist_t brauniger_iq_args[] = { + {0, 0, 0, 0, 0} +}; + +ff_vecs_t brauniger_iq_vecs = { + ff_type_serial, + rd_init, + NULL, + rd_deinit, + NULL, + data_read, + NULL, + NULL, + brauniger_iq_args +}; diff --git a/cetus.c b/cetus.c new file mode 100644 index 000000000..a85c9d487 --- /dev/null +++ b/cetus.c @@ -0,0 +1,427 @@ +/* + Read and write Cetus files. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "coldsync/palm.h" +#include "coldsync/pdb.h" + +#define MYNAME "Cetus" +#define MYTYPE 0x43577074 /* CWpt */ +#define MYCREATOR 0x63475053 /* cGPS */ + +#define NOTESZ 4096 +#define DESCSZ 4096 + +typedef enum { + WptEdit = 0, /* the position has been edited or it was */ + /* imported from another source */ + WptGPS2D = 1, /* retrieved from a GPS with a 2D fix */ + WptGPS3D = 2, /* retrieved from a GPS with a 3D fix */ + WptDGPS2D = 3, /* retrieved from a GPS with a 2D fix and DGPS signal */ + WptDGPS3D = 4, /* retrieved from a GPS with a 3D fix and DGPS signal */ + WptAverage = 5, /* averaging over 3D positions */ + WptCache = 50, /* this position is a geocache reference */ + WptGarmin = 70 /* this position was imported from a Garmin GPS */ + /* the icon field contains the garmin symbol number */ +} wpt_type; + +struct record { + char type; + + char readonly; + + pdb_32 latitude; /* Big endian, degrees*1e7, s=negative */ + pdb_32 longitude; /* same as lat; w=negative */ + pdb_32 elevation; /* Big endian, meters*100. blank=-1e8 */ + + pdb_16 year; /* sample time, UTC */ + unsigned char mon; + unsigned char day; + unsigned char hour; + unsigned char min; + unsigned char sec; + + /* accuracy and precision information for use where applicable */ + char sat; /* ff if averaged or unknown */ + pdb_16 pdop; /* pdop * 100 */ + pdb_16 hdop; + pdb_16 vdop; + pdb_16 dgpstime; + pdb_32 dgpsstn; + pdb_32 avgtime; + pdb_32 avgite; + + pdb_16 dopmask; + pdb_16 elevmask; + + pdb_16 radius; + pdb_32 distance; + + pdb_16 vyear; /* date visited */ + unsigned char vmon; + unsigned char vday; + unsigned char vhour; + unsigned char vmin; + unsigned char vsec; + + char flagged; + + pdb_32 icon; + pdb_16 category; +}; + +static FILE *file_in; +static FILE *file_out; +static const char *out_fname; +struct pdb *opdb; +struct pdb_record *opdb_rec; +static void *mkshort_wr_handle; + +static char *dbname = NULL; +static char *appendicon = NULL; + +static +arglist_t cetus_args[] = { + {"dbname", &dbname, "Database name", NULL, ARGTYPE_STRING }, + {"appendicon", &appendicon, "Append icon_descr to description.", + NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0 } +}; + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "rb", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); + if ( dbname ) { + xfree(dbname); + dbname = NULL; + } +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "wb", MYNAME); + out_fname = fname; +} + +static void +wr_deinit(void) +{ + fclose(file_out); + if ( dbname ) { + xfree(dbname); + dbname = NULL; + } +} + +static void +data_read(void) +{ + struct record *rec; + struct pdb *pdb; + struct pdb_record *pdb_rec; + char *vdata; + + if (NULL == (pdb = pdb_Read(fileno(file_in)))) { + fatal(MYNAME ": pdb_Read failed\n"); + } + + if ((pdb->creator != MYCREATOR) || (pdb->type != MYTYPE)) { + fatal(MYNAME ": Not a Cetus file.\n"); + } + + if (pdb->version < 1) { + fatal(MYNAME ": This file is from an obsolete beta version of Cetus GPS and is unsupported.\n"); + } + if (pdb->version > 1) { + fatal(MYNAME ": This file is from an unsupported newer version of Cetus GPS. It may be supported in a newer version of GPSBabel.\n"); + } + + for(pdb_rec = pdb->rec_index.rec; pdb_rec; pdb_rec=pdb_rec->next) { + waypoint *wpt_tmp; + + wpt_tmp = xcalloc(sizeof(*wpt_tmp),1); + + rec = (struct record *) pdb_rec->data; + if ( be_read32(&rec->elevation) == -100000000 ) { + wpt_tmp->altitude = unknown_alt; + } + else { + wpt_tmp->altitude = be_read32(&rec->elevation) / 100.0; + } + + wpt_tmp->longitude = be_read32(&rec->longitude) / 10000000.0; + wpt_tmp->latitude = be_read32(&rec->latitude) / 10000000.0; + + if (be_read16(&rec->year) != 0xff) { + struct tm tm; + + memset (&tm, sizeof(tm), 0); + tm.tm_min = rec->min; + tm.tm_hour = rec->hour; + tm.tm_mday = rec->day; + tm.tm_mon = rec->mon - 1; + tm.tm_year = be_read16(&rec->year) - 1900; + + wpt_tmp->creation_time = mktime(&tm); + + } + + vdata = (char *) pdb_rec->data + sizeof(*rec); + + wpt_tmp->shortname = xstrdup(vdata); + vdata = vdata + strlen(vdata) + 1; + + wpt_tmp->description = xstrdup(vdata); + vdata = vdata + strlen(vdata) + 1; + + wpt_tmp->notes = xstrdup(vdata); + + waypt_add(wpt_tmp); + + } + free_pdb(pdb); +} + + +static void +cetus_writewpt(const waypoint *wpt) +{ + struct record *rec; + static int ct; + struct tm *tm; + char *vdata; + char *desc_long; + char *desc_short; + char *desc; + + rec = xcalloc(sizeof(*rec)+18 + NOTESZ + DESCSZ,1); + + if (wpt->creation_time && (NULL != (tm = gmtime(&wpt->creation_time)))){ + rec->min = tm->tm_min; + rec->hour = tm->tm_hour; + rec->sec = tm->tm_sec; + rec->day = tm->tm_mday; + rec->mon = tm->tm_mon + 1; + be_write16( &rec->year, tm->tm_year + 1900); + } else { + rec->min = 0xff; + rec->hour = 0xff; + rec->sec = 0xff; + rec->day = 0xff; + rec->mon = 0xff; + be_write16(&rec->year, 0xff); + } + + be_write32(&rec->longitude, wpt->longitude * 10000000.0); + be_write32(&rec->latitude, wpt->latitude * 10000000.0); + if ( wpt->altitude == unknown_alt ) { + be_write32(&rec->elevation, -100000000U); + } + else { + be_write32(&rec->elevation, wpt->altitude * 100.0); + } + + be_write16( &rec->pdop, 0xffff ); + be_write16( &rec->hdop, 0xffff ); + be_write16( &rec->vdop, 0xffff ); + be_write16( &rec->dgpstime, 0xffff ); + be_write32( &rec->distance, 0xffffffff ); + + rec->vmin = 0xff; + rec->vhour = 0xff; + rec->vsec = 0xff; + rec->vday = 0xff; + rec->vmon = 0xff; + be_write16(&rec->vyear, 0xff); + + rec->sat = 0xff; + + vdata = (char *)rec + sizeof(*rec); + if ( wpt->shortname ) { + char *sn = str_utf8_to_cp1252(wpt->shortname); + strncpy( vdata, sn, 16 ); + vdata[15] = '\0'; + xfree(sn); + } + else { + vdata[0] ='\0'; + } + vdata += strlen( vdata ) + 1; + + if (wpt->gc_data.desc_short.utfstring) { + char *stripped_html = strip_html(&wpt->gc_data.desc_short); + desc_short = xstrdup("\n\n"); + desc_short = xstrappend(desc_short, str_utf8_to_cp1252(stripped_html)); + xfree(stripped_html); + } else { + desc_short = xstrdup(""); + } + + if (wpt->gc_data.desc_long.utfstring) { + char *stripped_html = strip_html(&wpt->gc_data.desc_long); + desc_long = xstrdup("\n\n"); + desc_long = xstrappend(desc_long, str_utf8_to_cp1252(stripped_html)); + xfree(stripped_html); + } else { + desc_long = xstrdup(""); + } + + desc = wpt->description ? str_utf8_to_cp1252(wpt->description) : + xstrdup(""); + + snprintf(vdata, DESCSZ, "%s%s%s", + desc, + desc_short, + desc_long); + + xfree(desc); + xfree(desc_short); + xfree(desc_long); + + if (appendicon && wpt->icon_descr) { + int left = DESCSZ - strlen( vdata ); + int ilen = strlen( wpt->icon_descr ); + if (ilen && left > (ilen+3)) { + strcat( vdata, " (" ); + strcat( vdata, wpt->icon_descr ); + strcat( vdata, ")" ); + } + } + vdata += strlen( vdata ) + 1; + + if (wpt->gc_data.hint) { + char *hint = str_utf8_to_cp1252(wpt->gc_data.hint); + rec->type = WptCache; + strncpy( vdata, hint, NOTESZ + 1 ) ; + xfree(hint); + vdata[NOTESZ] = '\0'; + } else { + rec->type = WptEdit; + vdata[0] ='\0'; + } + vdata += strlen( vdata ) + 1; + + opdb_rec = new_Record (0, 2, ct++, vdata-(char *)rec, (const ubyte *)rec); + + if (opdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create record\n"); + } + + if (pdb_AppendRecord(opdb, opdb_rec)) { + fatal(MYNAME ": libpdb couldn't append record\n"); + } + xfree(rec); +} + +struct hdr{ + char *wpt_name; + waypoint *wpt; +}; + +static +int +compare(const void *a, const void *b) +{ + const struct hdr *wa = a; + const struct hdr *wb = b; + + return strcmp(wa->wpt->shortname, wb->wpt->shortname); +} + +static void +data_write(void) +{ + int i, ct = waypt_count(); + struct hdr *htable, *bh; + queue *elem, *tmp; + extern queue waypt_head; + waypoint *waypointp; + mkshort_wr_handle = mkshort_new_handle(); + setshort_length(mkshort_wr_handle, 15); + setshort_whitespace_ok(mkshort_wr_handle, 0); + + if (NULL == (opdb = new_pdb())) { + fatal (MYNAME ": new_pdb failed\n"); + } + + if ( dbname ) { + strncpy( opdb->name, dbname, PDB_DBNAMELEN ); + } + else { + strncpy(opdb->name, out_fname, PDB_DBNAMELEN); + } + opdb->name[PDB_DBNAMELEN-1] = 0; + opdb->attributes = PDB_ATTR_BACKUP; + opdb->ctime = opdb->mtime = current_time() + 2082844800U; + opdb->type = MYTYPE; /* CWpt */ + opdb->creator = MYCREATOR; /* cGPS */ + opdb->version = 1; + + /* + * All this is to sort by waypoint names before going to Cetus. + * Turns out plain old strcmp will do the trick... + */ + + htable = xmalloc(ct * sizeof(*htable)); + bh = htable; + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + waypointp = (waypoint *) elem; + bh->wpt = waypointp; + if (global_opts.synthesize_shortnames && waypointp->description) { + if (waypointp->shortname) + xfree(waypointp->shortname); + waypointp->shortname = mkshort(mkshort_wr_handle, waypointp->description); + } + bh->wpt_name = waypointp->shortname; + bh ++; + } + qsort(htable, ct, sizeof(*bh), compare); + + for (i=0;i +#include +#include "palm.h" + +/* XXX - The functions declared INLINE, below, really ought to be inline + * functions. I'm not sure how to do this portably, though. + */ +#ifdef __GNUC__ +# define INLINE __inline__ +#else +# define INLINE +#endif /* __GNUC__ */ + +/* Functions for reading a value from an array of ubytes */ +extern INLINE ubyte peek_ubyte(const ubyte *buf); +extern INLINE uword peek_uword(const ubyte *buf); +extern INLINE udword peek_udword(const ubyte *buf); + +/* Functions for extracting values from an array of ubytes */ +extern INLINE ubyte get_ubyte(const ubyte **buf); +extern INLINE uword get_uword(const ubyte **buf); +extern INLINE udword get_udword(const ubyte **buf); + +/* Functions for writing values to an array of ubytes */ +extern INLINE void put_ubyte(ubyte **buf, const ubyte value); +extern INLINE void put_uword(ubyte **buf, const uword value); +extern INLINE void put_udword(ubyte **buf, const udword value); + +#if TIME +/* Functions for converting between DLP's time format and Unix's + * time_ts and the time_t-with-offset that the rest of the Palm stuff + * uses. + */ +extern time_t time_dlp2time_t(const struct dlp_time *dlpt); +extern udword time_dlp2palmtime(const struct dlp_time *dlpt); +extern void time_time_t2dlp(const time_t t, struct dlp_time *dlpt); +extern void time_palmtime2dlp(const udword palmt, struct dlp_time *dlpt); + +extern void debug_dump(FILE *outfile, const char *prefix, + const ubyte *buf, const udword len); +#endif +#endif /* _util_h_ */ + + /* This is for Emacs's benefit: + * Local Variables: *** + * fill-column: 75 *** + * End: *** + */ diff --git a/coldsync/pdb.c b/coldsync/pdb.c new file mode 100644 index 000000000..d923e57f9 --- /dev/null +++ b/coldsync/pdb.c @@ -0,0 +1,2025 @@ +/* pdb.c + * + * Functions for dealing with Palm databases and such. + * + * Copyright (C) 1999-2001, Andrew Arensburger. + * You may distribute this file under the terms of the Artistic + * License, as specified in the README file. + * + * $Id: pdb.c,v 1.6 2004/04/16 16:47:51 parkrrrr Exp $ + */ +/* XXX - The way zero-length records are handled is a bit of a kludge. They + * shouldn't normally exist, with the exception of expunged records. But, + * of course, a malformed conduit or something can create them. + * The half-assed way they're handled here is to a) not upload zero-length + * records to the Palm, b) warn the user if they're written to a file, c) + * provide a utility (in the p5-Palm package) to delete zero-length + * records. + */ +/* XXX - This is a library. It shouldn't print error messages. + * Add 'int pdb_errno'; define error numbers and error messages that go + * with them. + * Debugging messages should go to 'FILE *pdb_logfile'. + */ + +#include "config.h" +#include +#include /* For open() */ +#include +/* + * Unistd.h (indeed, read, write, and lseek) are not part of ISO C. + * Systems may not have unistd.h. While the below is tacky, Windows + * is the only system that we care about that has lseek and friends + * but doesn't have it prototyped. Systems with 64-bit file I/O but + * based on LP64 model (i.e. OS/X) _require_ the prototype for lseek. + */ +#if !defined (__WIN32__) +#include +#endif +#include +#include + +#if STDC_HEADERS +# include /* For strncat(), memcpy() et al. */ +#else /* STDC_HEADERS */ +# ifndef HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif /* HAVE_STRCHR */ +# ifndef HAVE_MEMCPY +# define memcpy(d,s,n) bcopy ((s), (d), (n)) +# define memmove(d,s,n) bcopy ((s), (d), (n)) +# endif /* HAVE_MEMCPY */ +#endif /* STDC_HEADERS */ + +/* XXX - Is this right? Should this be in the "else" clause, above? */ +#if HAVE_STRINGS_H +# include /* For bzero() */ +#endif /* HAVE_STRINGS_H */ + +#if HAVE_LIBINTL_H +# include /* For i18n */ +#endif /* HAVE_LIBINTL_H */ + +#include +#include "pdb.h" + +/* XXX - The functions declared INLINE, below, really ought to be inline + * functions. I'm not sure how to do this portably, though. + */ +#ifdef __GNUC__ +# define INLINE __inline__ +#else +# define INLINE +#endif /* __GNUC__ */ + +/* Functions for extracting values from an array of ubytes */ +extern INLINE ubyte get_ubyte(const ubyte **buf); +extern INLINE uword get_uword(const ubyte **buf); +extern INLINE udword get_udword(const ubyte **buf); + +/* Functions for writing values to an array of ubytes */ +extern INLINE void put_ubyte(ubyte **buf, const ubyte value); +extern INLINE void put_uword(ubyte **buf, const uword value); +extern INLINE void put_udword(ubyte **buf, const udword value); +extern void debug_dump(FILE *outfile, const char *prefix, + const ubyte *buf, const udword len); + +int pdb_trace = 0; /* Debugging level for PDB stuff */ +#define PDB_TRACE(n) if (pdb_trace >= (n)) + +/* Helper functions */ +static uword get_file_length(int fd); +int pdb_LoadHeader(int fd, struct pdb *db); + /* pdb_LoadHeader() is visible to other files */ +static int pdb_LoadRecListHeader(int fd, struct pdb *db); +static int pdb_LoadRsrcIndex(int fd, struct pdb *db); +static int pdb_LoadRecIndex(int fd, struct pdb *db); +static int pdb_LoadAppBlock(int fd, struct pdb *db); +static int pdb_LoadSortBlock(int fd, struct pdb *db); +static int pdb_LoadResources(int fd, struct pdb *db); +static int pdb_LoadRecords(int fd, struct pdb *db); + +/* merge_attributes + * Takes a record's flags and category, and merges them into a single byte, + * with the flags in the top nybble and the category in the bottom one + */ +static inline ubyte +merge_attributes(const ubyte flags, + const ubyte category) +{ + /* The PDB_REC_ARCHIVED flag is troublesome, since it overlaps the + * category field. The idea here is that if the record was deleted, + * then it doesn't have a category anymore, so the category part + * gets set to 0. + */ + if ((flags & PDB_REC_DELETED) == 0) + return (flags & 0xf0) | + (category & 0x0f); + else + return (flags & 0xf8); +} + +/* split_attributes + * The converse of merge_attributes(). Takes the combined field attributes + * and writes its contents to *flags and *category, using the same rules as + * merge_attributes(), above. + */ +static inline void +split_attributes(const ubyte attributes, + ubyte *flags, + ubyte *category) +{ + if ((attributes & PDB_REC_DELETED) == 0) + { + *flags = (attributes & 0xf0); + *category = (attributes & 0x0f); + } else { + *flags = (attributes & 0xf8); + *category = 0; + } + PDB_TRACE(6) + fprintf(stderr, "split 0x%02x into 0x%02x, 0x%02x\n", + attributes, *flags, *category); +} + +/* new_pdb + * struct pdb constructor. + */ +struct pdb * +new_pdb() +{ + struct pdb *retval; + + /* Allocate the new pdb */ + if ((retval = (struct pdb *) malloc(sizeof(struct pdb))) == NULL) + /* Out of memory */ + return NULL; + + /* Write zeros all over it, just for safety */ + memset((void *) retval, 0, sizeof(struct pdb)); + + return retval; +} + +/* pdb_FreeRecord + * Free a previously-allocated 'pdb_record'. This function wouldn't really + * be necessary, except that pdb_CopyRecord() returns a 'pdb_record'. + */ +void +pdb_FreeRecord(struct pdb_record *rec) +{ + if (rec->data != NULL) + free(rec->data); + free(rec); +} + +/* pdb_FreeResource + * Free a previously-allocated 'pdb_resource'. This function wouldn't + * really be necessary, except that pdb_CopyResource() returns a + * 'pdb_resource'. + */ +void +pdb_FreeResource(struct pdb_resource *rsrc) +{ + if (rsrc->data != NULL) + free(rsrc->data); + free(rsrc); +} + +/* free_pdb + * Cleanly free a struct pdb, and all of its subparts (destructor). + */ +void +free_pdb(struct pdb *db) +{ + PDB_TRACE(7) + fprintf(stderr, "Inside free_pdb(%p)\n", (void *) db); + + if (db == NULL) + /* Trivial case */ + return; + + /* Free the array of records/resources */ + if (IS_RSRC_DB(db)) + { + /* It's a resource database */ + struct pdb_resource *rsrc; + struct pdb_resource *next; + + PDB_TRACE(8) + fprintf(stderr, "Freeing resource list\n"); + + /* Walk the linked list, freeing as we go along */ + for (rsrc = db->rec_index.rsrc; + rsrc != NULL; + rsrc = next) + { + next = rsrc->next; /* Remember the next + * element on the list. We + * won't have a chance to + * look it up after this + * one has been free()d. + */ + + /* Free this element */ + pdb_FreeResource(rsrc); + } + } else { + /* It's a record database */ + struct pdb_record *rec; + struct pdb_record *next; + + PDB_TRACE(8) + fprintf(stderr, "Freeing record list\n"); + + /* Walk the linked list, freeing as we go along */ + for (rec = db->rec_index.rec; + rec != NULL; + rec = next) + { + next = rec->next; /* Remember the next + * element on the list. We + * won't have a chance to + * look it up after this + * one has been free()d. + */ + + /* Free this element */ + pdb_FreeRecord(rec); + } + } + + /* Free the sort block */ + if (db->sortinfo != NULL) + free(db->sortinfo); + + /* Free the app info block */ + if (db->appinfo != NULL) + free(db->appinfo); + + free(db); +} + +/* pdb_Read + * Read a PDB from the file descriptor 'fd'. This must already have been + * opened for reading and/or writing. + * + * Note: this function does not to any locking. The caller is responsible + * for that. + */ +struct pdb * +pdb_Read(int fd) +{ + int err; + struct pdb *retval; + + /* Create a new pdb to return */ + if ((retval = new_pdb()) == NULL) + { + return NULL; + } + + /* Find out how long the file is */ + retval->file_size = get_file_length(fd); + if (retval->file_size == ~0) + { + /* The file isn't seekable */ + fprintf(stderr, _("File isn't seekable.\n")); + free_pdb(retval); + return NULL; + } + + /* Load the header */ + if ((err = pdb_LoadHeader(fd, retval)) < 0) + { + fprintf(stderr, _("Can't load header.\n")); + free_pdb(retval); + return NULL; + } + + /* Load the record list header */ + if ((err = pdb_LoadRecListHeader(fd, retval)) < 0) + { + fprintf(stderr, _("Can't load record list header for " + "\"%.*s\".\n"), + PDB_DBNAMELEN, retval->name); + free_pdb(retval); + return NULL; + } + + /* Read the record/resource list */ + if (IS_RSRC_DB(retval)) + { + /* Read the resource index */ + if ((err = pdb_LoadRsrcIndex(fd, retval)) < 0) + { + fprintf(stderr, _("Can't read resource index for " + "\"%.*s\".\n"), + PDB_DBNAMELEN, retval->name); + free_pdb(retval); + return NULL; + } + } else { + /* Read the record index */ + if ((err = pdb_LoadRecIndex(fd, retval)) < 0) + { + fprintf(stderr, _("Can't read record index for " + "\"%.*s\".\n"), + PDB_DBNAMELEN, retval->name); + free_pdb(retval); + return NULL; + } + } + + /* In most PDBs, there are two NUL bytes here. They are allowed by + * the spec, but not mandated, and some PDBs don't have them. We'll + * ignore them for now, and have the appropriate pdb_Load*() + * function lseek() to the proper position. + */ + + /* Load the AppInfo block, if any */ + if ((err = pdb_LoadAppBlock(fd, retval)) < 0) + { + fprintf(stderr, _("Can't read AppInfo block for " + "\"%.*s\".\n"), + PDB_DBNAMELEN, retval->name); + free_pdb(retval); + return NULL; + } + + /* Load the sort block, if any */ + if ((err = pdb_LoadSortBlock(fd, retval)) < 0) + { + fprintf(stderr, _("Can't read sort block for " + "\"%.*s\".\n"), + PDB_DBNAMELEN, retval->name); + free_pdb(retval); + return NULL; + } + + /* Load the records themselves */ + if (IS_RSRC_DB(retval)) + { + /* Read the resources */ + if ((err = pdb_LoadResources(fd, retval)) < 0) + { + fprintf(stderr, _("Can't read resources for " + "\"%.*s\".\n"), + PDB_DBNAMELEN, retval->name); + free_pdb(retval); + return NULL; + } + } else { + /* Read the records */ + if ((err = pdb_LoadRecords(fd, retval)) < 0) + { + fprintf(stderr, _("Can't read records for " + "\"%.*s\".\n"), + PDB_DBNAMELEN, retval->name); + free_pdb(retval); + return NULL; + } + } + + return retval; /* Success */ +} + +/* pdb_Write + * Write 'db' to the file descriptor 'fd'. This must already have been + * opened for writing. + * + * Note that while you can open the backup file for reading and writing, + * read from it with pdb_Read() and save it with pdb_Write(), this is not + * recommended: if anything should go wrong at the wrong time (e.g., the + * disk fills up just as you're about to write the database back to disk), + * you will lose the entire backup. + * A better approach is to use a staging file: read from the backup file, + * write to a temporary file, then use rename() to move the temporary file + * onto the real one. Alternately, you can copy the original file to a + * temporary one, then open the temporary for both reading and writing. + * This might have some advantages, in that it allows you to lock a single + * file for the duration of the sync. + * + * Note: this function does not lock the file. The caller is responsible + * for that. + */ +int +pdb_Write(const struct pdb *db, + int fd) +{ + static ubyte header_buf[PDB_HEADER_LEN]; + /* Buffer for writing database header */ + static ubyte rlheader_buf[PDB_RECORDLIST_LEN]; + /* Buffer for writing the record list header */ + static ubyte nul_buf[2]; + /* Buffer for writing the two useless NULs */ + ubyte *wptr; /* Pointer into buffers, for writing */ + udword offset; /* The next offset we're interested in */ + + /* Initialize 'offset': the next variable-sized item will go after + * the header, after the index header, after the index, after the + * two useless NULs. + */ + offset = PDB_HEADER_LEN + PDB_RECORDLIST_LEN; + if (IS_RSRC_DB(db)) + offset += db->numrecs * PDB_RESOURCEIX_LEN; + else + offset += db->numrecs * PDB_RECORDIX_LEN; + offset += 2; /* Those two useless NUL bytes */ + + /** Write the database header **/ + + /* Construct the header in 'header_buf' */ + wptr = header_buf; + memcpy(wptr, db->name, PDB_DBNAMELEN); + wptr += PDB_DBNAMELEN; + put_uword(&wptr, (db->attributes & ~PDB_ATTR_OPEN)); + /* Clear the 'open' flag before writing */ + put_uword(&wptr, db->version); + put_udword(&wptr, db->ctime); + put_udword(&wptr, db->mtime); + put_udword(&wptr, db->baktime); + put_udword(&wptr, db->modnum); + if (db->appinfo == NULL) /* Write the AppInfo block, if any */ + /* This database doesn't have an AppInfo block */ + put_udword(&wptr, 0L); + else { + /* This database has an AppInfo block */ + put_udword(&wptr, offset); + offset += db->appinfo_len; + } + if (db->sortinfo == NULL) /* Write the sort block, if any */ + /* This database doesn't have a sort block */ + put_udword(&wptr, 0L); + else { + put_udword(&wptr, offset); + offset += db->sortinfo_len; + } + put_udword(&wptr, db->type); + put_udword(&wptr, db->creator); + put_udword(&wptr, db->uniqueIDseed); + + /* Write the database header */ + if (write(fd, header_buf, PDB_HEADER_LEN) != PDB_HEADER_LEN) + { + fprintf(stderr, _("%s: can't write database header for " + "\"%.*s\".\n"), + "pdb_Write", + PDB_DBNAMELEN, db->name); + perror("write"); + close(fd); + return -1; + } + + /** Write the record/resource index header **/ + /* Construct the record list header */ + wptr = rlheader_buf; + put_udword(&wptr, 0L); /* nextID */ + /* XXX - What is this? Should this be something + * other than 0? */ + put_uword(&wptr, db->numrecs); + + /* Write the record list header */ + if (write(fd, rlheader_buf, PDB_RECORDLIST_LEN) != PDB_RECORDLIST_LEN) + { + fprintf(stderr, _("%s: can't write record list header for " + "\"%.*s\".\n"), + "pdb_Write", + PDB_DBNAMELEN, db->name); + perror("write"); + return -1; + } + + /* Write the record/resource index */ + if (IS_RSRC_DB(db)) + { + /* It's a resource database */ + struct pdb_resource *rsrc; /* Current resource */ + + /* Go through the list of resources, writing each one */ + for (rsrc = db->rec_index.rsrc; + rsrc != NULL; + rsrc = rsrc->next) + { + static ubyte rsrcbuf[PDB_RESOURCEIX_LEN]; + /* Buffer to hold the resource + * index entry. + */ + + /* Construct the resource index entry */ + wptr = rsrcbuf; + put_udword(&wptr, rsrc->type); + put_uword(&wptr, rsrc->id); + put_udword(&wptr, offset); + + /* Write the resource index entry */ + if (write(fd, rsrcbuf, PDB_RESOURCEIX_LEN) != + PDB_RESOURCEIX_LEN) + { + fprintf(stderr, _("%s: Can't write resource " + "index entry for " + "\"%.*s\".\n"), + "pdb_Write", + PDB_DBNAMELEN, db->name); + perror("write"); + return -1; + } + + /* Bump 'offset' up to point to the offset of the + * next variable-sized thing in the file. + */ + offset += rsrc->data_len; + } + } else { + /* It's a record database */ + struct pdb_record *rec; /* Current record */ + + /* Go through the list of records, writing each one */ + for (rec = db->rec_index.rec; rec != NULL; rec = rec->next) + { + static ubyte recbuf[PDB_RECORDIX_LEN]; + /* Buffer to hold the record index + * entry. + */ + + /* Construct the record index entry */ + wptr = recbuf; + + /* Sanity check */ + if (rec->data_len == 0) + { + fprintf(stderr, + _("\"%.*s\" record 0x%08lx has " + "length 0.\n"), + PDB_DBNAMELEN, db->name, + rec->id); + } + + put_udword(&wptr, offset); + put_ubyte(&wptr, merge_attributes( + rec->flags, + rec->category)); + put_ubyte(&wptr, (char) ((rec->id >> 16) & 0xff)); + put_ubyte(&wptr, (char) ((rec->id >> 8) & 0xff)); + put_ubyte(&wptr, (char) (rec->id & 0xff)); + + /* Write the resource index entry */ + if (write(fd, recbuf, PDB_RECORDIX_LEN) != + PDB_RECORDIX_LEN) + { + fprintf(stderr, _("%s: Can't write record " + "index entry for " + "\"%.*s\".\n"), + "pdb_Write", + PDB_DBNAMELEN, db->name); + perror("write"); + return -1; + } + + /* Bump 'offset' up to point to the offset of the + * next variable-sized thing in the file. + */ + offset += rec->data_len; + } + } + + /* Write the two useless NUL bytes */ + nul_buf[0] = nul_buf[1] = '\0'; + if (write(fd, nul_buf, 2) != 2) + { + fprintf(stderr, _("%s: Can't write the two useless NULs to " + "\"%.*s\".\n"), + "pdb_Write", + PDB_DBNAMELEN, db->name); + perror("write"); + return -1; + } + + /* Write the AppInfo block, if any */ + if (db->appinfo != NULL) + { + if (write(fd, db->appinfo, db->appinfo_len) != + db->appinfo_len) + { + fprintf(stderr, _("%s: Can't write AppInfo block for " + "\"%.*s\".\n"), + "pdb_Write", + PDB_DBNAMELEN, db->name); + perror("write"); + return -1; + } + } + + /* Write the sort block, if any */ + if (db->sortinfo != NULL) + { + if (write(fd, db->sortinfo, db->sortinfo_len) != + db->sortinfo_len) + { + fprintf(stderr, _("%s: Can't write sort block for " + "\"%.*s\".\n"), + "pdb_Write", + PDB_DBNAMELEN, db->name); + perror("write"); + return -1; + } + } + + /* Write the record/resource data */ + if (IS_RSRC_DB(db)) + { + /* It's a resource database */ + struct pdb_resource *rsrc; + + /* Go through the list of resources, writing each one's + * data. + */ + for (rsrc = db->rec_index.rsrc; + rsrc != NULL; + rsrc = rsrc->next) + { + /* Write the data */ + if (write(fd, rsrc->data, rsrc->data_len) != + rsrc->data_len) + { + fprintf(stderr, _("%s: Can't write resource " + "data for \"%.*s\".\n"), + "pdb_Write", + PDB_DBNAMELEN, db->name); + perror("write"); + return -1; + } + } + } else { + /* It's a record database */ + struct pdb_record *rec; + + /* Go through the list of records, writing each one's data. */ + for (rec = db->rec_index.rec; rec != NULL; rec = rec->next) + { + /* Write the data */ + if (write(fd, rec->data, rec->data_len) != + rec->data_len) + { + fprintf(stderr, + _("%s: Can't write record data for " + "\"%.*s\".\n"), + "pdb_Write", + PDB_DBNAMELEN, db->name); + perror("write"); + return -1; + } + } + } + + return 0; /* Success */ +} + +#if 0 +/* pdb_FindRecordByID + * Find the record in 'db' whose ID is 'id'. Return a pointer to it. If no + * such record exists, or in case of error, returns NULL. + */ +struct pdb_record * +pdb_FindRecordByID( + const struct pdb *db, + const udword id) +{ + struct pdb_record *rec; + + /* Walk the list of records, comparing IDs */ + for (rec = db->rec_index.rec; rec != NULL; rec = rec->next) + { + if (rec->id == id) + return rec; + } + + return NULL; /* Couldn't find it */ +} + +/* pdb_FindRecordByIndex + * Find the 'index'th record in 'db', and return a pointer to it. If no + * such record exists, or in case of error, return NULL. + */ +struct pdb_record * +pdb_FindRecordByIndex( + const struct pdb *db, /* Database to look in */ + const uword index) /* Index of the record to look for */ +{ + struct pdb_record *rec; + int i; + + /* Walk the list, decrementing the count as we go along. If it + * reaches 0, we've found the record. + */ + rec = db->rec_index.rec; + for (i = index; i > 0; i--) + { + if (rec == NULL) + /* Oops! We've fallen off the end of the list */ + return NULL; + rec = rec->next; + } + + return rec; /* Success */ +} + +/* pdb_NextRecord + * Find the next record after 'rec' in 'db', and return a pointer to it. If + * 'rec' is the last record in the list, return NULL. + */ +struct pdb_record * +pdb_NextRecord(const struct pdb *db, /* Database to look in */ + const struct pdb_record *rec) + /* Return 'rec's successor */ +{ + return rec->next; +} + +/* pdb_DeleteRecordByID + * Find the record whose unique ID is 'id' and delete it from 'db'. If the + * record isn't found, well, that's okay; we wanted to delete it anyway. + * Returns 0 if successful, -1 in case of error. + */ +int +pdb_DeleteRecordByID( + struct pdb *db, + const udword id) +{ + struct pdb_record *rec; /* Record we're looking at */ + struct pdb_record *last; /* Last record we saw */ + + if (IS_RSRC_DB(db)) + /* This only works with record databases */ + return -1; + + /* Look through the list of records */ + last = NULL; /* Haven't seen any records yet */ + for (rec = db->rec_index.rec; rec != NULL; rec = rec->next) + { + /* See if the ID matches */ + if (rec->id == id) + { + /* Found it */ + + /* XXX - Presumably better to use pdb_FreeRecord() */ + /* Free 'rec's data */ + if (rec->data != NULL) + free(rec->data); + + /* Cut 'rec' out of the list. The first element of + * the list is a special case. + */ + if (last == NULL) + db->rec_index.rec = rec->next; + else + last->next = rec->next; + + free(rec); /* Free it */ + db->numrecs--; /* Decrement record count */ + + return 0; /* Success */ + } + + last = rec; /* Remember what we just saw */ + } + + /* Couldn't find it. Oh, well. Call it a success anyway. */ + return 0; +} +#endif + +/* pdb_AppendRecord + * Append a new record to 'db's record list. 'newrec' is not copied, so it + * is important that the caller not free it afterwards. + */ +/* XXX - Ought to make sure that the ID is unique */ +int +pdb_AppendRecord(struct pdb *db, + struct pdb_record *newrec) +{ + struct pdb_record *rec; + + /* Sanity check */ + if (IS_RSRC_DB(db)) + /* This only works with record databases */ + return -1; + + /* Check to see if the list is empty */ + if (db->rec_index.rec == NULL) + { + db->rec_index.rec = newrec; + newrec->next = NULL; + + db->numrecs++; /* Bump record counter */ + + return 0; /* Success */ + } + + /* Walk the list to find its end */ + for (rec = db->rec_index.rec; rec->next != NULL; rec = rec->next) + ; + rec->next = newrec; + newrec->next = NULL; + + db->numrecs++; /* Bump record counter */ + + return 0; /* Success */ +} + +/* pdb_AppendResource + * Append a new resource to 'db's resource list. 'newrsrc' is not copied, + * so it is important that the caller not free it afterwards. + */ +int +pdb_AppendResource(struct pdb *db, + struct pdb_resource *newrsrc) +{ + struct pdb_resource *rsrc; + + /* Sanity check */ + if (!IS_RSRC_DB(db)) + /* This only works with resource databases */ + return -1; + + /* Check to see if the list is empty */ + if (db->rec_index.rsrc == NULL) + { + db->rec_index.rsrc = newrsrc; + newrsrc->next = NULL; + + db->numrecs++; /* Bump resource counter */ + + return 0; /* Success */ + } + + /* Walk the list to find its end */ + for (rsrc = db->rec_index.rsrc; rsrc->next != NULL; rsrc = rsrc->next) + ; + rsrc->next = newrsrc; + newrsrc->next = NULL; + + db->numrecs++; /* Bump resource counter */ + + return 0; /* Success */ +} + +/* pdb_InsertRecord + * Insert 'newrec' into 'db', just after 'prev'. If 'prev' is NULL, + * 'newrec' is inserted at the beginning of the list. + * Returns 0 if successful, -1 otherwise. + * 'newrec' is not copied, so it is important that the caller not free it. + */ +int +pdb_InsertRecord(struct pdb *db, /* The database to insert into */ + struct pdb_record *prev, + /* Insert after this record */ + struct pdb_record *newrec) + /* The record to insert */ +{ + /* If 'prev' is NULL, insert at the beginning of the list */ + if (prev == NULL) + { + newrec->next = db->rec_index.rec; + db->rec_index.rec = newrec; + db->numrecs++; /* Increment record count */ + + return 0; /* Success */ + } + + /* XXX - This function doesn't actually check to make sure that + * 'prev' is in 'db'. You could really fuck yourself over with + * this. + * So make it a documented requirement. + */ + /* The new record goes in the middle of the list. Insert it. */ + newrec->next = prev->next; + prev->next = newrec; + db->numrecs++; /* Increment record count */ + + return 0; /* Success */ +} + +#if 0 +/* pdb_InsertResource + * Insert 'newrsrc' into 'db', just after 'prev'. If 'prev' is NULL, 'newrsrc' + * is inserted at the beginning of the list. + * Returns 0 if successful, -1 otherwise. + * 'newrec' is not copied, so it is important that the caller not free it. + */ +int +pdb_InsertResource(struct pdb *db, /* The database to insert into */ + struct pdb_resource *prev, + /* Insert after this resource */ + struct pdb_resource *newrsrc) + /* The resource to insert */ +{ + /* If 'prev' is NULL, insert at the beginning of the list */ + if (prev == NULL) + { + newrsrc->next = db->rec_index.rsrc; + db->rec_index.rsrc = newrsrc; + db->numrecs++; /* Increment record count */ + + return 0; /* Success */ + } + + /* XXX - This function doesn't actually check to make sure that + * 'prev' is in 'db'. You could really fuck yourself over with + * this. + * So make it a documented requirement. + */ + /* The new resource goes in the middle of the list. Insert it. */ + newrsrc->next = prev->next; + prev->next = newrsrc; + db->numrecs++; /* Increment record count */ + + return 0; /* Success */ +} +#endif + +/* new_Record + * Create a new record from the given arguments, and return a pointer to + * it. Returns NULL in case of error. + * The record data is copied, so the caller needs to take care of freeing + * 'data'. + * + * The 'attributes' and 'category' arguments are combined into one field: + * if the new record is deleted, then the category is silently dropped. + * Otherwise, the category occupies the bottom 4 bits of the + * attributes/category field. + */ +struct pdb_record * +new_Record(const ubyte flags, + const ubyte category, + const udword id, + const uword len, + const ubyte *data) +{ + struct pdb_record *retval; + + PDB_TRACE(6) + { + fprintf(stderr, "new_Record: Creating new record:\n"); + fprintf(stderr, "\tflags == 0x%02x\n", flags); + fprintf(stderr, "\tcategory == 0x%02x\n", category); + fprintf(stderr, "\tid == 0x%08lx\n", id); + fprintf(stderr, "\tlen == %d\n", len); + debug_dump(stderr, "NEW", data, len); + } + + /* Allocate the record to be returned */ + if ((retval = (struct pdb_record *) malloc(sizeof(struct pdb_record))) + == NULL) + { + fprintf(stderr, _("%s: Out of memory.\n"), + "new_Record"); + return NULL; + } + + /* Initialize the new record */ + retval->next = NULL; + retval->offset = 0L; + retval->flags = flags; + retval->category = category; + retval->id = id; + + /* Allocate space to put the record data */ + if (len == 0) + { + /* Special case: the record has no data (e.g., this is an + * expunged record). + */ + retval->data_len = len; + retval->data = NULL; + return retval; + } + + if ((retval->data = (ubyte *) malloc(len)) == NULL) + { + /* Couldn't allocate data portion of record */ + fprintf(stderr, _("%s: can't allocate data.\n"), + "new_Record"); + free(retval); + return NULL; + } + + /* Copy the data to the new record */ + retval->data_len = len; + memcpy(retval->data, data, len); + + return retval; /* Success */ +} + +/* new_Resource + * Create a new resource from the given arguments, and return a pointer to + * it. Returns NULL in case of error. + * The resource data is copied, so the caller needs to take care of freeing + * 'data'. + */ +struct pdb_resource * +new_Resource(const udword type, + const uword id, + const uword len, + const ubyte *data) +{ + struct pdb_resource *retval; + + PDB_TRACE(6) + { + fprintf(stderr, "new_Resource: Creating new resource:\n"); + fprintf(stderr, "\ttype == 0x%08lx (%c%c%c%c)\n", + type, + (int) ((type >> 24) & 0xff), + (int) ((type >> 16) & 0xff), + (int) ((type >> 8) & 0xff), + (int) (type & 0xff)); + fprintf(stderr, "\tid == 0x%04x\n", id); + fprintf(stderr, "\tlen == %d\n", len); + debug_dump(stderr, "NEW", data, len); + } + + /* Allocate the resource to be returned */ + if ((retval = (struct pdb_resource *) + malloc(sizeof(struct pdb_resource))) == NULL) + { + fprintf(stderr, _("%s: Out of memory.\n"), + "new_Resource"); + return NULL; + } + + /* Initialize the new resource */ + retval->next = NULL; + retval->offset = 0L; + retval->type = type; + retval->id = id; + + /* Allocate space to put the resource data */ + if (len == 0) + { + /* Special case: zero-length resource (dunno if this should + * ever happen, but this way we avoid malloc(0). + */ + retval->data_len = len; + retval->data = NULL; + return retval; + } + + if ((retval->data = (ubyte *) malloc(len)) == NULL) + { + /* Couldn't allocate data portion of resource */ + fprintf(stderr, _("%s: can't allocate data.\n"), + "new_Resource"); + free(retval); + return NULL; + } + + /* Copy the data to the new resource */ + retval->data_len = len; + memcpy(retval->data, data, len); + + return retval; /* Success */ +} + +/* pdb_CopyRecord + * Make a copy of record 'rec' in database 'db' (and its data), and return + * it. The new record is allocated by pdb_CopyRecord(), so the caller has + * to take care of freeing it. + * Returns a pointer to the new copy, or NULL in case of error. + */ +struct pdb_record *pdb_CopyRecord( + const struct pdb *db, + const struct pdb_record *rec) +{ + struct pdb_record *retval; + + /* Allocate the record to be returned */ + if ((retval = (struct pdb_record *) malloc(sizeof(struct pdb_record))) + == NULL) + { + fprintf(stderr, _("%s: Out of memory.\n"), + "pdb_CopyRecord"); + return NULL; + } + + retval->next = NULL; /* For cleanliness */ + + /* Copy the old record to the new copy */ + retval->offset = rec->offset; + retval->flags = rec->flags; + retval->category = rec->category; + retval->id = rec->id; + + /* Allocate space for the record data itself */ + if ((retval->data = (ubyte *) malloc(rec->data_len)) == NULL) + { + fprintf(stderr, _("%s: can't allocate record data for " + "\"%.*s\".\n"), + "pdb_CopyRecord", + PDB_DBNAMELEN, db->name); + free(retval); + return NULL; + } + + /* Copy the record data */ + retval->data_len = rec->data_len; + memcpy(retval->data, rec->data, retval->data_len); + + return retval; /* Success */ +} + +/* pdb_CopyResource + * Make a copy of resource 'rsrc' in database 'db' (and its data), and + * return it. The new record is allocated by pdb_CopyResource(), so the + * caller has to take care of freeing it. + * Returns a pointer to the new copy, or NULL in case of error. + */ +struct pdb_resource *pdb_CopyResource( + const struct pdb *db, + const struct pdb_resource *rsrc) +{ + struct pdb_resource *retval; + + /* Allocate the resource to be returned */ + if ((retval = (struct pdb_resource *) + malloc(sizeof(struct pdb_resource))) == NULL) + { + fprintf(stderr, _("%s: Out of memory.\n"), + "pdb_CopyResource"); + return NULL; + } + + retval->next = NULL; /* For cleanliness */ + + /* Copy the old resource to the new copy */ + retval->type = rsrc->type; + retval->id = rsrc->id; + retval->offset = rsrc->offset; + + /* Allocate space for the record data itself */ + if ((retval->data = (ubyte *) malloc(rsrc->data_len)) == NULL) + { + fprintf(stderr, _("%s: can't allocate resource data for " + "\"%.*s\".\n"), + "pdb_CopyResource", + PDB_DBNAMELEN, db->name); + free(retval); + return NULL; + } + + /* Copy the resource data */ + retval->data_len = rsrc->data_len; + memcpy(retval->data, rsrc->data, retval->data_len); + + return retval; /* Success */ +} + +/*** Helper functions ***/ + +/* get_file_length + * Return the length of a file, in bytes. In case of error, returns ~0. + */ +static uword +get_file_length(int fd) +{ + off_t here; + off_t eof; + + /* Get the current position within the file */ + here = lseek(fd, 0L, SEEK_CUR); + if (here < 0) + /* The file isn't seekable, presumably either because it + * isn't open, or because it's a pipe/socket/FIFO/tty. + */ + return ~0; + + /* Go to the end of the file */ + eof = lseek(fd, 0L, SEEK_END); + + /* And return to where we were before */ + lseek(fd, here, SEEK_SET); + + return eof - here; +} + +/* pdb_LoadHeader + * Read the header of a pdb file, and fill in the appropriate fields in + * 'db'. + */ +int +pdb_LoadHeader(int fd, + struct pdb *db) +{ + int err; + static ubyte buf[PDB_HEADER_LEN]; + /* Buffer to hold the file header */ + const ubyte *rptr; /* Pointer into buffers, for reading */ + + /* Read the header */ + if ((err = read(fd, buf, PDB_HEADER_LEN)) != PDB_HEADER_LEN) + { + perror("pdb_LoadHeader: read"); + return -1; + } + + /* Parse the database header */ + rptr = buf; + memcpy(db->name, buf, PDB_DBNAMELEN); + rptr += PDB_DBNAMELEN; + db->attributes = get_uword(&rptr); + db->version = get_uword(&rptr); + db->ctime = get_udword(&rptr); + db->mtime = get_udword(&rptr); + db->baktime = get_udword(&rptr); + db->modnum = get_udword(&rptr); + db->appinfo_offset = get_udword(&rptr); + db->sortinfo_offset = get_udword(&rptr); + db->type = get_udword(&rptr); + db->creator = get_udword(&rptr); + db->uniqueIDseed = get_udword(&rptr); + + PDB_TRACE(5) + { + time_t t; + + fprintf(stderr, "\tname: \"%s\"\n", db->name); + fprintf(stderr, "\tattributes: 0x%04x", db->attributes); + if (db->attributes & PDB_ATTR_RESDB) + fprintf(stderr, " RESDB"); + if (db->attributes & PDB_ATTR_RO) fprintf(stderr, " RO"); + if (db->attributes & PDB_ATTR_APPINFODIRTY) + fprintf(stderr, " APPINFODIRTY"); + if (db->attributes & PDB_ATTR_BACKUP) + fprintf(stderr, " BACKUP"); + if (db->attributes & PDB_ATTR_OKNEWER) + fprintf(stderr, " OKNEWER"); + if (db->attributes & PDB_ATTR_RESET) fprintf(stderr, " RESET"); + if (db->attributes & PDB_ATTR_NOCOPY) + fprintf(stderr, " NOCOPY"); + if (db->attributes & PDB_ATTR_STREAM) + fprintf(stderr, " STREAM"); + if (db->attributes & PDB_ATTR_OPEN) + fprintf(stderr, " OPEN"); + fprintf(stderr, "\n"); + fprintf(stderr, "\tversion: %u\n", db->version); + t = db->ctime - EPOCH_1904; + fprintf(stderr, "\tctime: %lu %s", db->ctime, + ctime(&t)); + t = db->mtime - EPOCH_1904; + fprintf(stderr, "\tmtime: %lu %s", db->mtime, + ctime(&t)); + t = db->baktime - EPOCH_1904; + fprintf(stderr, "\tbaktime: %lu %s", db->baktime, + ctime(&t)); + fprintf(stderr, "\tmodnum: %ld\n", db->modnum); + fprintf(stderr, "\tappinfo_offset: 0x%08lx\n", + db->appinfo_offset); + fprintf(stderr, "\tsortinfo_offset: 0x%08lx\n", + db->sortinfo_offset); + fprintf(stderr, "\ttype: '%c%c%c%c' (0x%08lx)\n", + (char) (db->type >> 24) & 0xff, + (char) (db->type >> 16) & 0xff, + (char) (db->type >> 8) & 0xff, + (char) db->type & 0xff, + db->type); + fprintf(stderr, "\tcreator: '%c%c%c%c' (0x%08lx)\n", + (char) (db->creator >> 24) & 0xff, + (char) (db->creator >> 16) & 0xff, + (char) (db->creator >> 8) & 0xff, + (char) db->creator & 0xff, + db->creator); + fprintf(stderr, "\tuniqueIDseed: %ld\n", db->uniqueIDseed); + } + + return 0; /* Success */ +} + +/* pdb_LoadRecListHeader + * Load the record list header from a pdb file, and fill in the appropriate + * fields in 'db'. + */ +static int +pdb_LoadRecListHeader(int fd, + struct pdb *db) +{ + int err; + static ubyte buf[PDB_RECORDLIST_LEN]; + const ubyte *rptr; /* Pointer into buffers, for reading */ + + /* Read the record list header */ + if ((err = read(fd, buf, PDB_RECORDLIST_LEN)) != PDB_RECORDLIST_LEN) + { + perror("pdb_LoadRecListHeader: read2"); + return -1; + } + + /* Parse the record list */ + rptr = buf; + db->next_reclistID = get_udword(&rptr); + db->numrecs = get_uword(&rptr); + + PDB_TRACE(6) + { + fprintf(stderr, "\tnextID: %ld\n", db->next_reclistID); + fprintf(stderr, "\tlen: %u\n", db->numrecs); + } + + return 0; +} + +/* pdb_LoadRsrcIndex + * Read the resource index from a resource database file, and fill in the + * appropriate fields in 'db'. + */ +static int +pdb_LoadRsrcIndex(int fd, + struct pdb *db) +{ + int i; + int err; + uword totalrsrcs; /* The real number of resources in the + * database. + */ + + totalrsrcs = db->numrecs; /* Get the number of resources in + * the database. It is necessary to + * remember this here because + * pdb_AppendResource() increments + * db->numrecs in the name of + * convenience. + */ + + if (totalrsrcs == 0) + { + /* There are no resources in this file */ + db->rec_index.rsrc = NULL; + return 0; + } + + /* Read the resource index */ + for (i = 0; i < totalrsrcs; i++) + { + static ubyte inbuf[PDB_RESOURCEIX_LEN]; + /* Input buffer */ + const ubyte *rptr; /* Pointer into buffers, for reading */ + struct pdb_resource *rsrc; + /* New resource entry */ + + /* Allocate the resource entry */ + if ((rsrc = (struct pdb_resource *) + malloc(sizeof(struct pdb_resource))) + == NULL) + return -1; + /* Scribble zeros all over it, just in case */ + memset((void *) rsrc, 0, sizeof(struct pdb_resource)); + + /* Read the next resource index entry */ + if ((err = read(fd, inbuf, PDB_RESOURCEIX_LEN)) != + PDB_RESOURCEIX_LEN) + return -1; + + /* Parse it */ + rptr = inbuf; + rsrc->type = get_udword(&rptr); + rsrc->id = get_uword(&rptr); + rsrc->offset = get_udword(&rptr); + + PDB_TRACE(6) + { + fprintf(stderr, + "\tResource %d: type '%c%c%c%c' (0x%08lx), " + "id %u, offset 0x%08lx\n", + i, + (char) (rsrc->type >> 24) & 0xff, + (char) (rsrc->type >> 16) & 0xff, + (char) (rsrc->type >> 8) & 0xff, + (char) rsrc->type & 0xff, + rsrc->type, + rsrc->id, + rsrc->offset); + } + + /* Append the new resource to the list */ + pdb_AppendResource(db, rsrc); /* XXX - Error-checking */ + db->numrecs = totalrsrcs; /* Kludge */ + } + + return 0; +} + +/* pdb_LoadRecIndex + * Read the record index from a record database file, and fill in the + * appropriate fields in 'db'. + */ +static int +pdb_LoadRecIndex(int fd, + struct pdb *db) +{ + int i; + int err; + uword totalrecs; /* The real number of records in the + * database. + */ + + totalrecs = db->numrecs; /* Get the number of records in the + * database. It is necessary to + * remember this here because + * pdb_AppendResource() increments + * db->numrecs in the name of + * convenience. + */ + + if (totalrecs == 0) + { + /* There are no records in this file */ + db->rec_index.rec = NULL; + return 0; + } + + /* Read the record index */ + /* XXX - It would be a Good Thing to check for zero-length records + * here. They've been known to appear as a result of a broken + * conduit. + */ + for (i = 0; i < totalrecs; i++) + { + static ubyte inbuf[PDB_RECORDIX_LEN]; + /* Input buffer */ + const ubyte *rptr; /* Pointer into buffers, for reading */ + struct pdb_record *rec; + /* New record entry */ + ubyte attributes; /* Combined flags+category field */ + + /* Allocate the record entry */ + if ((rec = (struct pdb_record *) + malloc(sizeof(struct pdb_record))) + == NULL) + { + fprintf(stderr, _("%s: Out of memory.\n"), + "pdb_LoadRecIndex"); + return -1; + } + + /* Scribble zeros all over it, just in case */ + memset((void *) rec, 0, sizeof(struct pdb_record)); + + /* Read the next record index entry */ + if ((err = read(fd, inbuf, PDB_RECORDIX_LEN)) != + PDB_RECORDIX_LEN) + { + fprintf(stderr, _("%s: error reading record index " + "entry for \"%.*s\" (%d bytes): " + "%d.\n"), + "LoadRecIndex", + PDB_DBNAMELEN, db->name, + PDB_RECORDIX_LEN, + err); + perror("read"); + free(rec); + return -1; + } + + /* Parse it */ + rptr = inbuf; + rec->offset = get_udword(&rptr); + attributes = get_ubyte(&rptr); + split_attributes(attributes, &(rec->flags), &(rec->category)); + + rec->id = + ((udword) (get_ubyte(&rptr) << 16)) | + ((udword) (get_ubyte(&rptr) << 8)) | + ((udword) get_ubyte(&rptr)); + + PDB_TRACE(6) + fprintf(stderr, + "\tRecord %d: offset 0x%08lx, flags 0x%02x, " + " category 0x%02x, ID 0x%08lx\n", + i, + rec->offset, + rec->flags, + rec->category, + rec->id); + + /* Append the new record to the database */ + pdb_AppendRecord(db, rec); /* XXX - Error-checking */ + db->numrecs = totalrecs; /* Kludge */ + } + + return 0; +} + +/* pdb_LoadAppBlock + * Read the AppInfo block from a database file, and fill in the appropriate + * fields in 'db'. If the file doesn't have an AppInfo block, set it to + * NULL. + */ +static int +pdb_LoadAppBlock(int fd, + struct pdb *db) +{ + int err; + localID next_off; /* Offset of the next thing in the file + * after the AppInfo block */ + off_t offset; /* Offset into file, for checking */ + + /* Check to see if there even *is* an AppInfo block */ + if (db->appinfo_offset == 0L) + { + /* Nope */ + db->appinfo_len = 0L; + db->appinfo = NULL; + return 0; + } + + /* Figure out how long the AppInfo block is, by comparing its + * offset to that of the next thing in the file. + */ + if (db->sortinfo_offset > 0L) + /* There's a sort block */ + next_off = db->sortinfo_offset; + else if (db->numrecs > 0) + { + /* There's no sort block, but there are records. Get the + * offset of the first one. + */ + if (IS_RSRC_DB(db)) + next_off = db->rec_index.rsrc->offset; + else + next_off = db->rec_index.rec->offset; + } else + /* There is neither sort block nor records, so the AppInfo + * block must go to the end of the file. + */ + next_off = db->file_size; + + /* Subtract the AppInfo block's offset from that of the next thing + * in the file to get the AppInfo block's length. + */ + db->appinfo_len = next_off - db->appinfo_offset; + + /* This is probably paranoid, but what the hell */ + if (db->appinfo_len == 0L) + { + /* An effective no-op */ + db->appinfo = NULL; + return 0; + } + + /* Now that we know the length of the AppInfo block, allocate space + * for it and read it. + */ + if ((db->appinfo = (ubyte *) malloc(db->appinfo_len)) == NULL) + { + fprintf(stderr, _("%s: Out of memory.\n"), + "pdb_LoadAppBlock"); + return -1; + } + + /* Just out of paranoia, make sure we're at the correct offset in + * the file. Since the two NULs may or may not have appeared in the + * file, the only thing that it makes sense to check is whether + * we've already passed the beginning of the AppInfo block, as + * given by its offset in the header. + */ + offset = lseek(fd, 0L, SEEK_CUR); /* Find out where we are */ + if (offset != db->appinfo_offset) + { + if (offset > db->appinfo_offset) + { + /* Oops! We're in the wrong place */ + fprintf(stderr, _("Warning: AppInfo block in \"%.*s\" " + "isn't where I thought it would " + "be.\n" + "Expected 0x%lx, but we're at " + "0x%lx.\n"), + PDB_DBNAMELEN, db->name, + db->appinfo_offset, (long) offset); + } + + /* Try to recover */ + offset = lseek(fd, db->appinfo_offset, SEEK_SET); + /* Go to where the AppInfo block + * ought to be */ + if (offset < 0) + { + /* Something's wrong */ + fprintf(stderr, _("Can't find the AppInfo block in " + "\"%.*s\"!\n"), + PDB_DBNAMELEN, db->name); + return -1; + } + } + + /* Read the AppInfo block */ + if ((err = read(fd, db->appinfo, db->appinfo_len)) != db->appinfo_len) + { + perror("pdb_LoadAppBlock: read"); + return -1; + } + PDB_TRACE(6) + debug_dump(stderr, "appinfo, db->appinfo_len); + + return 0; +} + +/* pdb_LoadSortBlock + * Read the sort block from a database file, and fill in the appropriate + * fields in 'db'. If the file doesn't have a sort block, set it to NULL. + * + * XXX - Largely untested, since not that many databases have sort blocks. + * But it's basically just a clone of pdb_LoadAppBlock(), so it should be + * okay. + */ +static int +pdb_LoadSortBlock(int fd, + struct pdb *db) +{ + int err; + localID next_off; /* Offset of the next thing in the file + * after the sort block */ + off_t offset; /* Offset into file, for checking */ + + /* Check to see if there even *is* a sort block */ + if (db->sortinfo_offset == 0L) + { + /* Nope */ + db->sortinfo_len = 0L; + db->sortinfo = NULL; + return 0; + } + + /* Figure out how long the sort block is, by comparing its + * offset to that of the next thing in the file. + */ + if (db->numrecs > 0) + { + /* There are records. Get the offset of the first one. + */ + if (IS_RSRC_DB(db)) + next_off = db->rec_index.rsrc->offset; + else + next_off = db->rec_index.rec->offset; + } else + /* There are no records, so the sort block must go to the + * end of the file. + */ + next_off = db->file_size; + + /* Subtract the sort block's offset from that of the next thing + * in the file to get the sort block's length. + */ + db->sortinfo_len = next_off - db->sortinfo_offset; + + /* This is probably paranoid, but what the hell */ + if (db->sortinfo_len == 0L) + { + /* An effective no-op */ + db->sortinfo = NULL; + return 0; + } + + /* Now that we know the length of the sort block, allocate space + * for it and read it. + */ + if ((db->sortinfo = (ubyte *) malloc(db->sortinfo_len)) == NULL) + { + fprintf(stderr, _("%s: Out of memory.\n"), + "pdb_LoadSortBlock"); + return -1; + } + + /* Just out of paranoia, make sure we're at the correct offset in + * the file. Since the two NULs may or may not have appeared in the + * file, the only thing that it makes sense to check is whether + * we've already passed the beginning of the sort block, as given + * by its offset in the header. + */ + offset = lseek(fd, 0L, SEEK_CUR); /* Find out where we are */ + if (offset != db->sortinfo_offset) + { + if (offset > db->sortinfo_offset) + { + /* Oops! We're in the wrong place */ + fprintf(stderr, _("Warning: sort block in \"%.*s\" " + "isn't where I thought it would " + "be.\n" + "Expected 0x%lx, but we're at " + "0x%lx.\n"), + PDB_DBNAMELEN, db->name, + db->sortinfo_offset, (long) offset); + } + + /* Try to recover */ + offset = lseek(fd, db->sortinfo_offset, SEEK_SET); + /* Go to where the sort block + * ought to be */ + if (offset < 0) + { + /* Something's wrong */ + fprintf(stderr, _("Can't find the sort block in " + "\"%.*s\"!\n"), + PDB_DBNAMELEN, db->name); + return -1; + } + } + + /* Read the sort block */ + if ((err = read(fd, db->sortinfo, db->sortinfo_len)) != + db->sortinfo_len) + { + perror("pdb_LoadSortBlock: read"); + return -1; + } + PDB_TRACE(6) + debug_dump(stderr, "sortinfo, db->sortinfo_len); + + return 0; +} + +/* pdb_LoadResources + * Read each resource in turn from a resource database file. + */ +static int +pdb_LoadResources(int fd, + struct pdb *db) +{ + int i; + int err; + struct pdb_resource *rsrc; + + /* This assumes that the resource list has already been created by + * 'pdb_LoadRsrcIndex()'. + */ + for (i = 0, rsrc = db->rec_index.rsrc; + i < db->numrecs; + i++, rsrc = rsrc->next) + { + off_t offset; /* Current offset, for checking */ + udword next_off; /* Offset of next resource in file */ + + /* Sanity check: make sure we haven't stepped off the end + * of the list. + */ + if (rsrc == NULL) + { + fprintf(stderr, _("Hey! I can't find the %dth " + "resource in \"%.*s\"!\n"), + i, + PDB_DBNAMELEN, db->name); + return -1; + } + + PDB_TRACE(5) + fprintf(stderr, + "Reading resource %d (type '%c%c%c%c')\n", + i, + (char) (rsrc->type >> 24) & 0xff, + (char) (rsrc->type >> 16) & 0xff, + (char) (rsrc->type >> 8) & 0xff, + (char) rsrc->type & 0xff); + + /* Out of paranoia, make sure we're in the right place. + * Since the two NULs may or may not have appeared in the + * file, the only thing that it makes sense to check is + * whether we've already passed the beginning of the + * resource, as given by its offset in the resource index. + */ + offset = lseek(fd, 0L, SEEK_CUR); + /* Find out where we are now */ + if (offset != rsrc->offset) + { + if (offset > rsrc->offset) + { + fprintf(stderr, _("Warning: resource %d in " + "\"%.*s\" isn't where " + "I thought it would be.\n" + "Expected 0x%lx, but we're " + "at 0x%lx.\n"), + i, + PDB_DBNAMELEN, db->name, + rsrc->offset, (long) offset); + } + + /* Try to recover */ + offset = lseek(fd, rsrc->offset, SEEK_SET); + /* Go to where this + * resource ought to be. + */ + if (offset < 0) + { + /* Something's wrong */ + fprintf(stderr, _("Can't find resource %d in " + "\"%.*s\".\n"), + i, + PDB_DBNAMELEN, db->name); + return -1; + } + } + + /* Okay, now that we're in the right place, find out what + * the next thing in the file is: its offset will tell us + * how much to read. + * It's debatable whether 'i' or 'rsrc' should be + * authoritative for determining the offset of the next + * resource. I'm going to choose 'rsrc', since I think + * that's more likely to be immune to fencepost errors. The + * two should, however, be equivalent. In fact, it might be + * a Good Thing to add a check to make sure. + */ + if (rsrc->next == NULL) + { + /* This is the last resource in the file, so it + * goes to the end of the file. + */ + next_off = db->file_size; + } else { + /* This isn't the last resource. Find the next + * one's offset. + */ + next_off = rsrc->next->offset; + } + + /* Subtract this resource's index from that of the next + * thing, to get the size of this resource. + */ + rsrc->data_len = next_off - rsrc->offset; + + /* Allocate space for this resource */ + if ((rsrc->data = (ubyte *) malloc(rsrc->data_len)) == NULL) + { + fprintf(stderr, _("%s: Out of memory.\n"), + "pdb_LoadResources"); + return -1; + } + + /* Read the resource */ + if ((err = read(fd, rsrc->data, rsrc->data_len)) != + rsrc->data_len) + { + fprintf(stderr, _("Can't read resource %d in " + "\"%.*s\".\n"), + i, + PDB_DBNAMELEN, db->name); + perror("pdb_LoadResources: read"); + return -1; + } + PDB_TRACE(6) + { + fprintf(stderr, "Contents of resource %d:\n", i); + debug_dump(stderr, "data, + rsrc->data_len); + } + } + + return 0; /* Success */ +} + +/* pdb_LoadRecords + * Read each record in turn from a record database file. + */ +static int +pdb_LoadRecords(int fd, + struct pdb *db) +{ + int i; + int err; + struct pdb_record *rec; + + /* This assumes that the record list has already been created by + * 'pdb_LoadRecIndex()'. + */ + for (i = 0, rec = db->rec_index.rec; + i < db->numrecs; + i++, rec = rec->next) + { + off_t offset; /* Current offset, for checking */ + localID next_off; /* Offset of next resource in file */ + + /* Sanity check: make sure we haven't stepped off the end + * of the list. + */ + if (rec == NULL) + { + fprintf(stderr, _("Hey! I can't find the %dth " + "record in \"%.*s\"!\n"), + i, + PDB_DBNAMELEN, db->name); + return -1; + } + + PDB_TRACE(5) + fprintf(stderr, "Reading record %d (id 0x%08lx)\n", + i, rec->id); + + /* Out of paranoia, make sure we're in the right place. + * Since the two NULs may or may not have appeared in the + * file, the only thing that it makes sense to check is + * whether we've already passed the beginning of the + * record, as given by its offset in the record index. + */ + offset = lseek(fd, 0L, SEEK_CUR); + /* Find out where we are now */ + if (offset != rec->offset) + { + if (offset > rec->offset) + { + fprintf(stderr, _("Warning: record %d in " + "\"%.*s\" isn't where " + "I thought it would be.\n" + "Expected 0x%lx, but we're " + "at 0x%lx.\n"), + i, + PDB_DBNAMELEN, db->name, + rec->offset, (long) offset); + } + + /* Try to recover */ + offset = lseek(fd, rec->offset, SEEK_SET); + /* Go to where this record + * ought to be. */ + if (offset < 0) + { + /* Something's wrong */ + fprintf(stderr, _("Can't find record %d in " + "\"%.*s\".\n"), + i, + PDB_DBNAMELEN, db->name); + return -1; + } + } + + /* Okay, now that we're in the right place, find out what + * the next thing in the file is: its offset will tell us + * how much to read. + * It's debatable whether 'i' or 'rec' should be + * authoritative for determining the offset of the next + * resource. I'm going to choose 'rec', since I think + * that's more likely to be immune from fencepost errors. + * The two should, however, be equivalent. In fact, it + * might be a Good Thing to add a check to make sure. + */ + if (rec->next == NULL) + { + /* This is the last record in the file, so it goes + * to the end of the file. + */ + next_off = db->file_size; + } else { + /* This isn't the last record. Find the next one's + * offset. + */ + next_off = rec->next->offset; + } + + /* Subtract this record's index from that of the next one, + * to get the size of this record. + */ + rec->data_len = next_off - rec->offset; + + /* Allocate space for this record + * If there's a record with length zero, don't pass that to + * malloc(). This is most likely due to a broken conduit. + * XXX - The Right Thing to do would be not to read + * zero-length records, but that would involve fixing the + * record index. + */ + if (rec->data_len > 0) + { + if ((rec->data = (ubyte *) malloc(rec->data_len)) == + NULL) + { + fprintf(stderr, _("%s: Out of memory.\n"), + "pdb_LoadRecords"); + return -1; + } + + /* Read the record */ + if ((err = read(fd, rec->data, rec->data_len)) != + rec->data_len) + { + fprintf(stderr, _("Can't read record %d in " + "\"%.*s\".\n"), + i, + PDB_DBNAMELEN, db->name); + perror("pdb_LoadRecords: read"); + return -1; + } + + PDB_TRACE(6) + { + fprintf(stderr, "Contents of record %d:\n", i); + debug_dump(stderr, "data, + rec->data_len); + } + } + } + + return 0; /* Success */ +} + + /* This is for Emacs's benefit: + * Local Variables: *** + * fill-column: 75 *** + * End: *** + */ diff --git a/coldsync/pdb.h b/coldsync/pdb.h new file mode 100644 index 000000000..1d34d23c4 --- /dev/null +++ b/coldsync/pdb.h @@ -0,0 +1,273 @@ +/* pdb.h + * + * Definitions and such for Palm databases. + * + * Copyright (C) 1999-2000, Andrew Arensburger. + * You may distribute this file under the terms of the Artistic + * License, as specified in the README file. + * + * $Id: pdb.h,v 1.1 2002/08/16 06:13:10 robertl Exp $ + */ +#ifndef _pdb_h_ +#define _pdb_h_ + +/* XXX - Add a type (and support functions) for those ubitquitous + * 4-character IDs. + */ + +#define EPOCH_1904 2082844800L /* Difference, in seconds, between + * Palm's epoch (Jan. 1, 1904) and + * Unix's epoch (Jan. 1, 1970). + */ + +#define PDB_DBNAMELEN 32 /* Length of name field in database + * header */ + +/* Database attribute flags */ +#define PDB_ATTR_RESDB 0x0001 /* This is a resource database. + * Resource databases are usually + * saved in files with ".prc" + * extensions. Other databases are + * saved with a ".pdb" extension. + */ +#define PDB_ATTR_RO 0x0002 /* Read-only database */ +#define PDB_ATTR_APPINFODIRTY 0x0004 /* App info block is dirty */ +#define PDB_ATTR_BACKUP 0x0008 /* Back up the database if no + * app-specific conduit exists */ +#define PDB_ATTR_OKNEWER 0x0010 /* Tells the backup conduit that + * it's okay to install a newer + * version of this database with a + * different name if this one is + * open. Usually used for the + * Graffiti Shortcuts database. + */ +#define PDB_ATTR_RESET 0x0020 /* Reset the Palm after the + * database is installed */ +#define PDB_ATTR_NOCOPY 0x0040 /* Database should not be copied(?) */ +#define PDB_ATTR_STREAM 0x0080 /* Database is used for file stream + * implementation(?). + */ +#define PDB_ATTR_OPEN 0x8000 /* Database is open */ + +/* Record attributes + * These are the attributes that individual records in a database can have. + * I've taken the liberty of giving them different names from Palm's, since + * Palm's names are rather confusing. + * + * PDB_REC_PRIVATE is set on a record that has been marked "private" by the + * user. It is not encrypted, and if the desktop asks for this record, the + * Palm will not refuse or ask for a password. In short, the Palm needs to + * trust the desktop. + * + * PDB_REC_DIRTY is set on a record whose contents have been modified since + * the last sync. If the user deletes a record without modifying it, + * PDB_REC_DIRTY will not be set, but if he modifies it, then deletes it, + * then both PDB_REC_DIRTY and PDB_REC_DELETED will be set. + * + * PDB_REC_DELETED is set on a record that has been deleted by the user + * since the last sync. Unfortunately, it looks as if not all applications + * are polite enough to set this flag, so you have to go with + * PDB_REC_ARCHIVE and PDB_REC_EXPUNGED. + * + * If the user chose the "Save archive copy on PC" option when deleting a + * record, then the PDB_REC_ARCHIVE bit will be set on the record (with any + * luck, so will PDB_REC_DELETED). + * + * If the user did not choose the "Save archive copy on PC" option when + * deleting a record, the PDB_REC_EXPUNGED bit will be set on the record + * (as will PDB_REC_DELETED, perhaps). Apparently, what happens is this: + * when the user deletes a record, a copy is left around so that HotSync + * will know to delete this record. However, if the user chose not to keep + * a copy, then, in order to conserve memory, the Palm will delete the + * record data, although it will keep a copy of the record header for + * HotSync. + */ +#define PDB_REC_EXPUNGED 0x80 /* The contents of this record have + * been deleted, leaving only the + * record info. (Palm calls this + * 'dlpRecAttrDeleted'.) + */ +#define PDB_REC_DIRTY 0x40 /* Record has been modified. (Palm + * calls this 'dlpRecAttrDirty'.) + */ +#define PDB_REC_DELETED 0x20 /* This record has been deleted. + * (Palm calls this + * 'dlpRecAttrBusy'.) + */ +#define PDB_REC_PRIVATE 0x10 /* Record is private: don't show to + * anyone without asking for a + * password. (Palm calls this + * 'dlpRecAttrSecret'.) + */ +#define PDB_REC_ARCHIVE 0x08 /* This record should be archived + * at the next sync. (Palm calls + * this 'dlpRecAttrArchived'.) + */ + +typedef udword localID; /* Local (card-relative) chunk ID + * (basically, a pointer that can + * be used as a unique ID). + */ + +#define PDB_HEADER_LEN 72 /* Length of header in a file */ +#define PDB_RECORDLIST_LEN 6 /* Length of record index header in + * file */ + +/* pdb_record + * A plain old record, containing arbitrary data. + */ +struct pdb_record +{ + struct pdb_record *next; /* Next record on linked list */ + localID offset; /* Offset of record in file */ + ubyte flags; /* Record flags (PDB_REC_*) */ + ubyte category; /* Record's category */ + udword id; /* Record's unique ID. Actually, + * only the bottom 3 bytes are + * stored in the file, but for + * everything else, it's much + * easier to just consider this a + * 32-bit integer. + */ + uword data_len; /* Length of this record */ + ubyte *data; /* This record's data */ +}; +#define PDB_RECORDIX_LEN 8 /* Size of a pdb_record in a file */ + +/* pdb_resource + * Mac hackers should feel at home here: the type of a resource is really a + * 4-character category identifier, and the ID is an integer within that + * category. + */ +struct pdb_resource +{ + struct pdb_resource *next; /* Next resource on linked list */ + udword type; /* Resource type */ + uword id; /* Resource ID */ + localID offset; /* Offset of resource in file */ + uword data_len; /* Length of this resource */ + ubyte *data; /* This resource's data */ +}; +#define PDB_RESOURCEIX_LEN 10 /* Size of a pdb_resource in a file */ + +/* pdb + * Structure of a Palm database (file), both resource databases (.prc) and + * record databases (.pdb). + */ +struct pdb +{ + long file_size; /* Total length of file */ + + char name[PDB_DBNAMELEN]; /* Database name */ + uword attributes; /* Database attributes */ + uword version; /* Database version */ + + udword ctime; /* Creation time */ + udword mtime; /* Time of last modification */ + udword baktime; /* Time of last backup */ + udword modnum; /* Modification number */ + /* XXX - What exactly is the modification number? + * Does it get incremented each time you make any + * kind of change to the database? + */ + localID appinfo_offset; /* Offset of AppInfo block in the + * file */ + localID sortinfo_offset; /* Offset of sort block in the file */ + + udword type; /* Database type */ + udword creator; /* Database creator */ + + udword uniqueIDseed; /* Used to generate unique IDs for + * records and resources. Only the + * lower 3 bytes are used. The high + * byte is for alignment. + */ + + localID next_reclistID; /* ID of next record index in the + * file. In practice, this field is + * always zero. + */ + uword numrecs; /* Number of records/resources in + * the file. + */ + + long appinfo_len; /* Length of AppInfo block */ + void *appinfo; /* Optional AppInfo block */ + long sortinfo_len; /* Length of sort block */ + void *sortinfo; /* Optional sort block */ + + /* Record/resource list. Each of these is actually a linked list, + * to make it easy to insert and delete records. + */ + union { + struct pdb_record *rec; + struct pdb_resource *rsrc; + } rec_index; +}; + +/* Convenience macros */ +#define IS_RSRC_DB(db) ((db)->attributes & PDB_ATTR_RESDB) + /* Is this a resource database? If + * not, it must be a record + * database. + */ + +extern int pdb_trace; /* Debugging level for PDB stuff */ + +extern struct pdb *new_pdb(); +extern void free_pdb(struct pdb *db); +extern void pdb_FreeRecord(struct pdb_record *rec); +extern void pdb_FreeResource(struct pdb_resource *rsrc); +extern struct pdb *pdb_Read(int fd); /* Load a pdb from a file. */ +extern int pdb_Write(const struct pdb *db, int fd); + /* Write a pdb to a file */ +extern struct pdb_record *pdb_FindRecordByID( + const struct pdb *db, + const udword id); +extern struct pdb_record *pdb_FindRecordByIndex( + const struct pdb *db, + const uword index); +extern int pdb_DeleteRecordByID( + struct pdb *db, + const udword id); +extern int pdb_AppendRecord(struct pdb *db, struct pdb_record *newrec); +extern int pdb_AppendResource(struct pdb *db, struct pdb_resource *newrsrc); +extern int pdb_InsertRecord( + struct pdb *db, + struct pdb_record *prev, + struct pdb_record *newrec); +extern int pdb_InsertResource( + struct pdb *db, + struct pdb_resource *prev, + struct pdb_resource *newrsrc); +extern struct pdb_record *new_Record( + const ubyte attributes, + const ubyte category, + const udword id, + const uword len, + const ubyte *data); +extern struct pdb_resource *new_Resource( + const udword type, + const uword id, + const uword len, + const ubyte *data); +extern struct pdb_record *pdb_CopyRecord( + const struct pdb *db, + const struct pdb_record *rec); +extern struct pdb_resource *pdb_CopyResource( + const struct pdb *db, + const struct pdb_resource *rsrc); +extern int pdb_LoadHeader(int fd, struct pdb *db); + +/* XXX - Functions to write: +pdb_setAppInfo set the appinfo block +pdb_setSortInfo set the sortinfo block +*/ + +#endif /* _pdb_h_ */ + + /* This is for Emacs's benefit: + * Local Variables: *** + * fill-column: 75 *** + * End: *** + */ diff --git a/coldsync/util.c b/coldsync/util.c new file mode 100644 index 000000000..984e22b74 --- /dev/null +++ b/coldsync/util.c @@ -0,0 +1,290 @@ +/* util.c + * + * Misc. utility functions. + * + * Copyright (C) 1999, Andrew Arensburger. + * You may distribute this file under the terms of the Artistic + * License, as specified in the README file. + * + * The get_*() functions are used to extract values out of strings of + * ubytes and convert them to the native format. + * The put_*() functions, conversely, are used to take a value in the + * native format, convert them to Palm (big-endian) format, and write + * them to a ubyte string. + * + * $Id: util.c,v 1.3 2004/01/18 01:24:41 robertl Exp $ + */ + +#include "config.h" +#include +#include /* For isprint() */ +#include + +#ifndef EPOCH_1904 +# define EPOCH_1904 2082844800L /* Difference, in seconds, between + * Palm's epoch (Jan. 1, 1904) and + * Unix's epoch (Jan. 1, 1970). + */ +#endif /* EPOCH_1904 */ + +/* XXX - Most of the functions below really ought to be inlined. Not sure + * how to do this portably, though. + */ + +INLINE ubyte +peek_ubyte(const ubyte *buf) +{ + return buf[0]; +} + +INLINE uword +peek_uword(const ubyte *buf) +{ + return ((uword) buf[0] << 8) | + buf[1]; +} + +INLINE udword +peek_udword(const ubyte *buf) +{ + return ((uword) buf[0] << 24) | + ((uword) buf[1] << 16) | + ((uword) buf[2] << 8) | + buf[3]; +} + +INLINE ubyte +get_ubyte(const ubyte **buf) +{ + ubyte retval; + + retval = peek_ubyte(*buf); + *buf += SIZEOF_UBYTE; + + return retval; +} + +INLINE void +put_ubyte(ubyte **buf, ubyte value) +{ + **buf = value; + ++(*buf); +} + +INLINE uword +get_uword(const ubyte **buf) +{ + uword retval; + + retval = peek_uword(*buf); + *buf += SIZEOF_UWORD; + + return retval; +} + +INLINE void +put_uword(ubyte **buf, uword value) +{ + **buf = (value >> 8) & 0xff; + ++(*buf); + **buf = value & 0xff; + ++(*buf); +} + +INLINE udword +get_udword(const ubyte **buf) +{ + udword retval; + + retval = peek_udword(*buf); + *buf += SIZEOF_UDWORD; + + return retval; +} + +INLINE void +put_udword(ubyte **buf, udword value) +{ + **buf = (value >> 24) & 0xff; + ++(*buf); + **buf = (value >> 16) & 0xff; + ++(*buf); + **buf = (value >> 8) & 0xff; + ++(*buf); + **buf = value & 0xff; + ++(*buf); +} +#if TIME +/* XXX - Figure out the timezone hairiness: + * Palms don't have timezones. Hence, the Palm's epoch is Jan. 1, 1904 in + * the local timezone. + * Unless you're syncing across the network, in which case its epoch is + * Jan. 1, 1904 in the timezone it happens to be in (which may not be the + * same as the desktop's timezone). + * Except that there are (I'm sure) tools that add timezones to the Palm. + * These should be consulted. + * Times generated locally are in the local timezone (i.e., the one that + * the desktop machine is in). + */ + +/* time_dlp2time_t + * Convert the DLP time structure into a Unix time_t, and return it. + */ +time_t +time_dlp2time_t(const struct dlp_time *dlpt) +{ + struct tm tm; + + /* Convert the dlp_time into a struct tm, then just use mktime() to + * do the conversion. + */ + tm.tm_sec = dlpt->second; + tm.tm_min = dlpt->minute; + tm.tm_hour = dlpt->hour; + tm.tm_mday = dlpt->day; + tm.tm_mon = dlpt->month - 1; + tm.tm_year = dlpt->year - 1900; + tm.tm_wday = 0; + tm.tm_yday = 0; + tm.tm_isdst = 0; +#if HAVE_TM_ZONE + tm.tm_gmtoff = 0; + tm.tm_zone = NULL; +#else +/* XXX - ANSI doesn't allow #warning, and we're not using the timezone for + * anything yet. + */ +/* #warning You do not have tm_zone */ +#endif + + return mktime(&tm); +} + +/* time_dlp2palmtime + * Convert a DLP time structure into a Palm time_t (number of seconds since + * Jan. 1. 1904), and return it. + */ +udword +time_dlp2palmtime(const struct dlp_time *dlpt) +{ + time_t now; /* The time, as a Unix time_t */ + struct tm tm; + + /* Convert the dlp_time into a struct tm, use mktime() to do the + * conversion, and add the difference in epochs. + */ + tm.tm_sec = dlpt->second; + tm.tm_min = dlpt->minute; + tm.tm_hour = dlpt->hour; + tm.tm_mday = dlpt->day; + tm.tm_mon = dlpt->month - 1; + tm.tm_year = dlpt->year - 1900; + tm.tm_wday = 0; + tm.tm_yday = 0; + tm.tm_isdst = 0; +#if HAVE_TM_ZONE + tm.tm_gmtoff = 0; + tm.tm_zone = NULL; +#endif + + now = mktime(&tm); + now += EPOCH_1904; + + return now; +} + +/* time_time_t2dlp + * Convert a Unix time_t into a DLP time structure. Put the result in + * 'dlpt'. + */ +void +time_time_t2dlp(const time_t t, + struct dlp_time *dlpt) +{ + struct tm *tm; + + tm = localtime(&t); /* Break 't' down into components */ + + /* Copy the relevant fields over to 'dlpt' */ + dlpt->year = tm->tm_year + 1900; + dlpt->month = tm->tm_mon + 1; + dlpt->day = tm->tm_mday; + dlpt->hour = tm->tm_hour; + dlpt->minute = tm->tm_min; + dlpt->second = tm->tm_sec; +} + +/* time_palmtime2dlp + + * Convert a Palm time (seconds since the Jan. 1, 1904) to a DLP time + * structure. Put the result in 'dlpt'. + */ +void +time_palmtime2dlp(const udword palmt, + struct dlp_time *dlpt) +{ + struct tm *tm; +time_t t; + + /* Convert the Palm time to a Unix time_t */ + t = palmt - EPOCH_1904; + + /* Break the Unix time_t into components */ + tm = localtime(&t); + + /* Copy the relevant fields over to 'dlpt' */ + dlpt->year = tm->tm_year + 1900; + dlpt->month = tm->tm_mon + 1; + dlpt->day = tm->tm_mday; + dlpt->hour = tm->tm_hour; + dlpt->minute = tm->tm_min; + dlpt->second = tm->tm_sec; +} +#endif + +/* debug_dump + * Dump the contents of an array of ubytes to stderr, for debugging. + */ +void +debug_dump(FILE *outfile, const char *prefix, + const ubyte *buf, const udword len) +{ + unsigned int lineoff; + + for (lineoff = 0; lineoff < len; lineoff += 16) + { + int i; + + fprintf(outfile, "%s ", prefix); + for (i = 0; i < 16; i++) + { + if (lineoff + i < len) + { + /* Regular bytes */ + fprintf(outfile, "%02x ", buf[lineoff+i]); + } else { + /* Filler at the end of the line */ + fprintf(outfile, " "); + } + } + fprintf(outfile, " | "); + for (i = 0; i < 16; i++) + { + if (lineoff + i < len) + { + /* Regular bytes */ + if (isprint(buf[lineoff+i])) + fprintf(outfile, "%c", buf[lineoff+i]); + else + fprintf(outfile, "."); + } else + break; + } + fprintf(outfile, "\n"); + } +} + /* This is for Emacs's benefit: + * Local Variables: *** + * fill-column: 75 *** + * End: *** + */ diff --git a/contrib/correctCoordinates.pl b/contrib/correctCoordinates.pl new file mode 100644 index 000000000..baaf61307 --- /dev/null +++ b/contrib/correctCoordinates.pl @@ -0,0 +1,100 @@ +#!/usr/bin/perl + +############################################################################################################ +# +# GPX Coordinate corrector +# 3/17/2004 +# +# Takes a GPX Spinner-formatted CorrectedCaches.txt file and substitutes the coordinates into a GPX file +# most likely from a Geocaching pocket query, based on the short name (GCXXXX). +# Useful for updating coordinates for puzzle caches or changing to the next stage of a multi-cache. +# Caches that appear in the corrections file but are not in the GPX are ignored. +# +# Usage: +# correctCoordinates.pl my.gpx CorrectedCaches.txt > corrected.gpx +# +# requires XML::Twig +# +# Jeff Boulter +# +############################################################################################################ + +use strict; +use XML::Twig; + +my $fname = $ARGV[0]; +my $correctFile = $ARGV[1]; + +open(CORR, $correctFile) || die "can't find corrections file: $!"; + +my %correct; + +while () +{ + s/\#.*//; + tr/\r//d; + chomp; + my $line = trim($_); + if ($line) + { +# print "\"$line\"\n"; + my($wp, $lat, $lon) = split(/\,/, $line); +# print "coords: $wp $lat $lon\n"; + + $correct{$wp} = {'lat' => coordsToDec(trim($lat)), 'lon' => coordsToDec(trim($lon))}; + } +} + +close(CORR); + +my $twig = XML::Twig->new( + twig_roots => { 'wpt' => \&wpt, + }, + twig_print_outside_roots => 1, # print the rest +); + +$twig->parsefile($fname); # build the twig + +sub trim +{ + my $str = $_[0]; + $str =~ s/\s*(.*\S)\s*/$1/; + return $str; +} + +sub coordsToDec +{ + my $CoordString = @_[0]; + my $Result = 0; + if ($CoordString =~ /\s*([N|S|E|W])\D*(\d+)\D*([\d|.]+)/i) { + my $Direction = uc($1); + $Result = $2 + $3 / 60.; + if ($Direction eq 'S' || $Direction eq 'W') { + $Result = -$Result; + } + } + elsif ($CoordString =~ /\s*-{0,1}\d+\.\d+/) { + $Result = $CoordString; + } + return $Result; +} + + + sub wpt +{ + my( $t, $wpt)= @_; # arguments for all twig_handlers + my $title = $wpt->first_child( 'name')->text; # find the title + + if ($correct{$title}) + { +# print STDERR "correcting " . $wpt->first_child( 'urlname')->text . "\n"; + $wpt->set_att('lat' => $correct{$title}->{'lat'}); + $wpt->set_att('lon' => $correct{$title}->{'lon'}); + } + + # bug in Twig doesn't keep > escaped + $wpt->subs_text( qr{>}, '&ent( ">")'); + + $wpt->flush; # outputs the section and frees memory + } + diff --git a/contrib/gpx2xfig b/contrib/gpx2xfig new file mode 100644 index 000000000..edd43cc22 --- /dev/null +++ b/contrib/gpx2xfig @@ -0,0 +1,73 @@ +From: David Slimp +Date 02/09/04 +Subject: [Gpsbabel-misc] gpx2xfig and transparent gif + +Hello All, + +I don't know if anyone would be interested in this or not, +but I've created a small perl script that will convert a gpx +file to an xfig data file, so I could then take track +information and edit in a visual way, and then using fig2dev +I create a transparent gif of my track/route. + +I was planning to use this as an overlay for a Yahoo or +MapQuest map, but after driving a couple miles and then +trying to fit my track path over the Yahoo map for that area +it seemed to be a bit off -- rotation wise. At first I +thought it might be the difference between true north and +magnetic north, but appearantly not. + +Anyway, in case anyone out there might benefit from this or +want to work on it more here's my script and sample linux +command lines: + +==================== gpx2xfig =============================== +#!/usr/bin/perl -w +# +# gpx2xfig - converts GPS gpx file to xfig vector file +# +# author: David Slimp +# created: 20040206 +# updated: 20040208 + +$VERSION=".001"; + +($infl,$outfl)=@ARGV; + +open(IN,"$infl") or die "$!"; +open(OUT,">$outfl") or die "$!"; + +while () { + s/creator != MYCREATOR) || (pdb->type != MYTYPE)) { + fatal(MYNAME ": Not a CoPilot file.\n"); + } + + for(pdb_rec = pdb->rec_index.rec; pdb_rec; pdb_rec=pdb_rec->next) { + waypoint *wpt_tmp; + char *vdata; + + wpt_tmp = xcalloc(sizeof(*wpt_tmp),1); + + rec = (struct record *) pdb_rec->data; + wpt_tmp->longitude = + -pdb_read_double(&rec->longitude) * conv; + wpt_tmp->latitude = + pdb_read_double(&rec->latitude) * conv; + wpt_tmp->altitude = + pdb_read_double(&rec->elevation) * .3048; + + vdata = (char *) pdb_rec->data + sizeof(*rec); + + wpt_tmp->shortname = xstrdup(vdata); + vdata = vdata + strlen(vdata) + 1; + + wpt_tmp->description = xstrdup(vdata); + vdata = vdata + strlen(vdata) + 1; + + wpt_tmp->notes = xstrdup(vdata); + + waypt_add(wpt_tmp); + + } + free_pdb(pdb); +} + + +static void +copilot_writewpt(const waypoint *wpt) +{ + struct record *rec; + static int ct = 0; + char *vdata; + + rec = xcalloc(sizeof(*rec)+1141,1); + + pdb_write_double(&rec->latitude, wpt->latitude / conv); + pdb_write_double(&rec->longitude, + -wpt->longitude / conv); + pdb_write_double(&rec->elevation, + wpt->altitude / .3048); + pdb_write_double(&rec->magvar, 0); + + vdata = (char *)rec + sizeof(*rec); + if ( wpt->shortname ) { + strncpy( vdata, wpt->shortname, 10 ); + vdata[9] = '\0'; + } + else { + vdata[0] ='\0'; + } + vdata += strlen( vdata ) + 1; + if ( wpt->description ) { + strncpy( vdata, wpt->description, 100 ); + vdata[99] = '\0'; + } + else { + vdata[0] ='\0'; + } + vdata += strlen( vdata ) + 1; + + if ( wpt->notes ) { + strncpy( vdata, wpt->notes, 1000 ); + vdata[999] = '\0'; + } + else { + vdata[0] ='\0'; + } + vdata += strlen( vdata ) + 1; + + opdb_rec = new_Record (0, 2, ct++, vdata-(char *)rec, (const ubyte *)rec); + + if (opdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create record\n"); + } + + if (pdb_AppendRecord(opdb, opdb_rec)) { + fatal(MYNAME ": libpdb couldn't append record\n"); + } + xfree(rec); +} + +static void +data_write(void) +{ + if (NULL == (opdb = new_pdb())) { + fatal (MYNAME ": new_pdb failed\n"); + } + + strncpy(opdb->name, out_fname, PDB_DBNAMELEN); + opdb->name[PDB_DBNAMELEN-1] = 0; + opdb->attributes = PDB_ATTR_BACKUP; + opdb->ctime = opdb->mtime = current_time() + 2082844800U; + opdb->type = MYTYPE; + opdb->creator = MYCREATOR; + opdb->version = 0; + + waypt_disp_all(copilot_writewpt); + + pdb_Write(opdb, fileno(file_out)); +} + + +ff_vecs_t copilot_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL +}; diff --git a/csv_util.c b/csv_util.c new file mode 100644 index 000000000..4d426382c --- /dev/null +++ b/csv_util.c @@ -0,0 +1,1128 @@ +/* + Utilities for parsing Character Separated Value files (CSV) + + Copyright (C) 2002 Alex Mottram (geo_alexm at cox-internet.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include "defs.h" +#include "csv_util.h" +#include "grtcirc.h" + +#define MYNAME "CSV_UTIL" + +/* macros */ +#define LAT_DIR(a) a < 0.0 ? 'S' : 'N' +#define LON_DIR(a) a < 0.0 ? 'W' : 'E' +#define NONULL(a) a ? a : "" +#define ISWHITESPACE(a) ((a == ' ') || (a == '\t')) + +/* convert excel time (days since 1900) to time_t and back again */ +#define EXCEL_TO_TIMET(a) ((a - 25569.0) * 86400.0) +#define TIMET_TO_EXCEL(a) ((a / 86400.0) + 25569.0) + +extern char *xcsv_urlbase; +extern char *prefer_shortnames; + +static double pathdist = 0; +static double oldlon = 999; +static double oldlat = 999; + +static int waypt_out_count; + +/*********************************************************************/ +/* csv_stringclean() - remove any unwanted characters from string. */ +/* returns copy of string. */ +/* usage: p = csv_stringclean(stringtoclean, "&,\"") */ +/* (strip out ampersands, commas, and quotes. */ +/*********************************************************************/ +char * +#ifdef DEBUG_MEM +CSV_STRINGCLEAN(const char *string, const char *chararray, DEBUG_PARAMS) +#else +csv_stringclean(const char *string, const char *chararray) +#endif +{ + char * p1; + char * p2; + const char * cp; + char * tmp = xxstrdup(string,file,line); + + if ((! string) || (! chararray)) { + return (tmp); + } + + /* p2 - end of the original string */ + p2 = tmp + strlen(tmp); + + cp = chararray; + + while (*cp) { + p1 = tmp; + while (*p1) { + if (*cp == *p1) { + /* we don't want this character! */ + strncpy(p1, p1 + 1, (p2 - p1)); + p1[p2 - p1] = '\0'; + } + p1++; + } + cp++; + } + + return (tmp); +} + +/***********************************************************************************/ +/* csv_stringtrim() - trim whitespace and leading and trailing enclosures (quotes) */ +/* returns a copy of the modified string */ +/* usage: p = csv_stringtrim(string, "\"", 0) */ +/***********************************************************************************/ +char * +#ifdef DEBUG_MEM +CSV_STRINGTRIM(const char *string, const char *enclosure, int strip_max, DEBUG_PARAMS) +#else +csv_stringtrim(const char *string, const char *enclosure, int strip_max) +#endif +{ + static const char *p1 = NULL; + char *p2 = NULL; + char * tmp = xxstrdup(string,file,line); + size_t elen; + int stripped = 0; + + if (!strlen(string)) { + return (tmp); + } + + if (!enclosure) { + elen = 0; + } else { + elen = strlen(enclosure); + } + + p2 = tmp + strlen(tmp) - 1; + p1 = tmp; + + /* trim off trailing whitespace */ + while ((p2 > p1) && isspace(*p2)) { + p2--; + } + + /* advance p1 past any leading whitespace */ + while ((p1 < p2) && (isspace(*p1))) { + p1++; + } + + /* if no maximum strippage, assign a reasonable value to max */ + strip_max = strip_max ? strip_max : 9999; + + /* if we have enclosures, skip past them in pairs */ + if (elen) { + while ( + (stripped < strip_max) && + ((size_t) (p2 - p1) >= elen) && + (strncmp(p1, enclosure, elen) == 0) && + (strncmp((p2 - elen + 1), enclosure, elen) == 0)) { + p2 -= elen; + p1 += elen; + stripped++; + } + } + + /* copy what's left over back into tmp. */ + strncpy(tmp, p1, (p2 - p1) + 1); + tmp[(p2 - p1) + 1] = '\0'; + + return (tmp); +} + +/*****************************************************************************/ +/* csv_lineparse() - extract data fields from a delimited string. designed */ +/* to handle quoted and delimited data within quotes. */ +/* returns temporary COPY of delimited data field (use it */ +/* or lose it on the next call). */ +/* usage: p = csv_lineparse(string, ",", "\"", line) [initial call] */ +/* p = csv_lineparse(NULL, ",", "\"", line) [subsequent calls] */ +/*****************************************************************************/ +char * +csv_lineparse(const char *stringstart, const char *delimited_by, + const char *enclosed_in, const int line_no) +{ + const char *sp; + static const char *p = NULL; + static char *tmp = NULL; + size_t dlen = 0, elen = 0; + int enclosedepth = 0; + short int dfound; + short int hyper_whitespace_delimiter = 0; + + if (tmp) { + xfree(tmp); + tmp = NULL; + } + + if (strcmp(delimited_by, "\\w") == 0) + hyper_whitespace_delimiter = 1; + + if (!p) { + /* first pass thru */ + p = stringstart; + + if (!p) { + /* last pass out */ + return (NULL); + } + } + + /* the beginning of the string we start with (this pass) */ + sp = p; + + /* length of delimiters and enclosures */ + if ((delimited_by) && (!hyper_whitespace_delimiter)) + dlen = strlen(delimited_by); + if (enclosed_in) + elen = strlen(enclosed_in); + + dfound = 0; + + while ((*p) && (!dfound)) { + if ((elen) && (strncmp(p, enclosed_in, elen) == 0)) { + if (enclosedepth) + enclosedepth--; + else + enclosedepth++; + } + + if (!enclosedepth) { + if ((dlen) && (strncmp(p, delimited_by, dlen) == 0)) { + dfound = 1; + } else if ((hyper_whitespace_delimiter) && (ISWHITESPACE(*p))) { + dfound = 1; + while (ISWHITESPACE(*p)) + p++; + } else { + p++; + } + } + } + + /* allocate enough space for this data field */ + tmp = xcalloc((p - sp) + 1, sizeof(char)); + + strncpy(tmp, sp, (p - sp)); + tmp[p - sp] = '\0'; + + if (dfound) { + /* skip over the delimited_by */ + p += dlen; + } else { + /* end of the line */ + p = NULL; + } + + if (enclosedepth != 0) { + warning(MYNAME + ": Warning- Unbalanced Field Enclosures (%s) on line %d\n", + enclosed_in, line_no); + } + + return (tmp); +} + +/*****************************************************************************/ +/* dec_to_intdeg() - convert decimal degrees to integer degreees */ +/* usage: i = dec_to_intdeg(31.1234, 1); */ +/* i = dec_to_intdeg(91.1234, 0); */ +/*****************************************************************************/ +static int +dec_to_intdeg(const double d, const int islat) +{ + int ideg = 0; + + if (islat) { + ideg = (2147483647) - (d * 8388608); + } else { + ideg = (2147483647) - (fabs(d) * 8388608) + 1; + } + + return(ideg); +} + +/*****************************************************************************/ +/* intdeg_to_dec() - convert integer degrees to decimal degreees */ +/* usage: lat = dec_to_intdeg(ilat, 1); */ +/* lon = dec_to_intdeg(ilon, 0); */ +/*****************************************************************************/ +static double +intdeg_to_dec(const int ideg, const int islat) +{ + double d; + + if (islat) { + d = ((2147483647) - ideg) / (double)8388608; + } else { + d = ((-2147483647-1) + ideg) / (double)8388608; + } + + return(d); +} + +/*****************************************************************************/ +/* decdir_to_dec() - convert a decimal/direction value into pure decimal. */ +/* usage: lat = decdir_to_dec("W90.1234"); */ +/* lat = decdir_to_dec("30.1234N"); */ +/*****************************************************************************/ +static double +decdir_to_dec(const char * decdir) +{ + char *p; + const char *cp; + double rval; + int sign = 0; + + cp = &decdir[0]; + + if ((*cp == 'W') || (*cp == 'S')) + sign = -1; + else + if ((*cp == 'N') || (*cp == 'E')) + sign = 1; + + rval = sign ? strtod(&decdir[1], &p) : strtod(&decdir[0], &p); + + if (sign == 0) { + if ((*p == 'W') || (*p == 'S')) + sign = -1; + else + if ((*p == 'N') || (*p == 'E')) + sign = 1; + } + + return(rval * sign); +} + + +/***************************************************************************** + * human_to_dec() - convert a "human-readable" lat and/or lon to decimal + * usage: human_to_dec( "N 41° 09.12' W 085° 09.36'", &lat, &lon ); + * human_to_dec( "41 9 5.652 N", &lat, &lon ); + *****************************************************************************/ + +static void +human_to_dec( const char *instr, double *outlat, double *outlon ) +{ + double unk[3] = {999,999,999}; + double lat[3] = {999,999,999}; + double lon[3] = {999,999,999}; + int latsign = 0; + int lonsign = 0; + + const char *cur; + double *numres = unk; + int numind = 0; + + cur = instr; + + while ( cur && *cur ) { + switch (*cur) { + case 'n': case 's': case 'N': case 'S': + if ( unk[0] != 999 ) { + numind = 0; + numres = unk; + lat[0] = unk[0]; + lat[1] = unk[1]; + lat[2] = unk[2]; + unk[0] = unk[1] = unk[2] = 999; + } + else { + numres = lat; + numind = 0; + lat[0] = lat[1] = lat[2] = 999; + } + + if ( *cur == 'n' || *cur == 'N' ) + latsign = 1; + else + latsign = -1; + cur++; + break; + case 'w': case 'e': case 'W': case 'E': + if ( unk[0] != 999 ) { + numind = 0; + numres = unk; + lon[0] = unk[0]; + lon[1] = unk[1]; + lon[2] = unk[2]; + unk[0] = unk[1] = unk[2] = 999; + } + else { + numres = lon; + numind = 0; + lon[0] = lon[1] = lon[2] = 999; + } + + if ( *cur == 'e' || *cur == 'E' ) + lonsign = 1; + else + lonsign = -1; + cur++; + break; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case '0': case '.': + numres[numind] = atof(cur); + while (cur && *cur && strchr("1234567890.",*cur)) cur++; + break; + default: + if (numres[numind] != 999) { + numind++; + if ( numind > 2 ) { + numres = unk; + numind = 0; + } + } + cur++; + break; + } + } + + if ( outlat ) { + if ( lat[0] != 999 ) *outlat = lat[0]; + if ( lat[1] != 999 ) *outlat += lat[1]/60.0; + if ( lat[2] != 999 ) *outlat += lat[2]/3600.0; + if ( latsign ) *outlat *= latsign; + } + if ( outlon ) { + if ( lon[0] != 999 ) *outlon = lon[0]; + if ( lon[1] != 999 ) *outlon += lon[1]/60.0; + if ( lon[2] != 999 ) *outlon += lon[2]/3600.0; + if ( lonsign ) *outlon *= lonsign; + } +} + +/* + * dec_to_human - convert decimal degrees to human readable + */ + +void +dec_to_human( char *buff, const char *format, const char *dirs, double val ) +{ + char *subformat = NULL; + const char *formatptr = NULL; + char *percent = NULL; + char *type = NULL; + + int index = 0; + int intvals[3] = {0,0,0}; + double dblvals[3] = {0,0,0}; + int sign = 0; + + sign = (val < 0) ? 0 : 1; + + dblvals[0] = fabs(val); + intvals[0] = (int)dblvals[0]; + dblvals[1] = 60*(dblvals[0]-intvals[0]); + intvals[1] = (int)dblvals[1]; + dblvals[2] = 60*(dblvals[1]-intvals[1]); + intvals[2] = (int)dblvals[2]; + + subformat = xmalloc( strlen(format)+2); + formatptr = format; + + buff[0] = '\0'; + + while ( formatptr && *formatptr ) { + strcpy( subformat, formatptr ); + percent = strchr( subformat, '%' ); + if ( percent ) { + type = percent+1+strcspn( percent+1, "cdiouxXeEfgG%" ); + *(type+1) = '\0'; + switch( *type ) { + case 'c': + sprintf( buff+strlen(buff), subformat, dirs[sign] ); + break; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (index>2) fatal(MYNAME ": too many format specifiers\n"); + sprintf( buff+strlen(buff), subformat, intvals[index]); + index++; + break; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + if (index>2) fatal(MYNAME ": too many format specifiers\n"); + sprintf( buff+strlen(buff), subformat, dblvals[index]); + index++; + break; + case '%': + sprintf( buff+strlen(buff), subformat ); + break; + default: + fatal(MYNAME ": invalid format specifier\n"); + break; + + } + } + else { + sprintf( buff+strlen(buff), subformat ); + } + formatptr += strlen(subformat); + } + + xfree(subformat); +} + +/*****************************************************************************/ +/* xcsv_file_init() - prepare xcsv_file for first use. */ +/*****************************************************************************/ +void +xcsv_file_init(void) +{ + memset(&xcsv_file, '\0', sizeof(xcsv_file_t)); + + QUEUE_INIT(&xcsv_file.prologue); + QUEUE_INIT(&xcsv_file.epilogue); + + QUEUE_INIT(&xcsv_file.ifield); + /* ofield is alloced to allow pointing back at ifields + * where applicable. + */ + xcsv_file.ofield = xcalloc(sizeof(queue), 1); + QUEUE_INIT(xcsv_file.ofield); + /* + * Provide a sane default for CSV _files_. + */ + xcsv_file.type = ff_type_file; + + xcsv_file.mkshort_handle = mkshort_new_handle(); +} + +/*****************************************************************************/ +/* xcsv_ifield_add() - add input field to ifield queue. */ +/* usage: xcsv_ifield_add("DESCRIPTION", "", "%s") */ +/*****************************************************************************/ +void +xcsv_ifield_add(char *key, char *val, char *pfc) +{ + field_map_t *fmp = xcalloc(sizeof(*fmp), 1); + + fmp->key = key; + fmp->val = val; + fmp->printfc = pfc; + + ENQUEUE_TAIL(&xcsv_file.ifield, &fmp->Q); + xcsv_file.ifield_ct++; +} + +/*****************************************************************************/ +/* xcsv_ofield_add() - add output field to ofield queue. */ +/* usage: xcsv_ofield_add("LAT_DECIMAL", "", "%08.5lf") */ +/*****************************************************************************/ +void +xcsv_ofield_add(char *key, char *val, char *pfc) +{ + field_map_t *fmp = xcalloc(sizeof(*fmp), 1); + + fmp->key = key; + fmp->val = val; + fmp->printfc = pfc; + + ENQUEUE_TAIL(xcsv_file.ofield, &fmp->Q); + xcsv_file.ofield_ct++; +} + +/*****************************************************************************/ +/* xcsv_prologue_add() - add prologue line to prologue queue */ +/* usage: xcsv_prologue_add("Four score and seven years ago today,") */ +/*****************************************************************************/ +void +xcsv_prologue_add(char *prologue) +{ + ogue_t* ogp = xcalloc(sizeof(*ogp), 1); + + ogp->val = prologue; + ENQUEUE_TAIL(&xcsv_file.prologue, &ogp->Q); + xcsv_file.prologue_lines++; +} + +/*****************************************************************************/ +/* xcsv_epilogue_add() - add epilogue line to epilogue queue */ +/* usage: xcsv_epilogue_add("shall not perish from the earth.") */ +/*****************************************************************************/ +void +xcsv_epilogue_add(char *epilogue) +{ + ogue_t * ogp = xcalloc(sizeof(*ogp), 1); + + ogp->val = epilogue; + ENQUEUE_TAIL(&xcsv_file.epilogue, &ogp->Q); + xcsv_file.epilogue_lines++; +} + +/*****************************************************************************/ +/* xcsv_parse_val() - parse incoming data into the waypt structure. */ +/* usage: xcsv_parse_val("-123.34", *waypt, *field_map) */ +/*****************************************************************************/ +static void +xcsv_parse_val(const char *s, waypoint *wpt, const field_map_t *fmp) +{ + if (strcmp(fmp->key, "IGNORE") == 0) { + /* IGNORE -- Categorically ignore this... */ + } else + if (strcmp(fmp->key, "CONSTANT") == 0) { + /* CONSTANT -- Ignore on Input... */ + } else + if (strcmp(fmp->key, "ANYNAME") == 0) { + /* ANYNAME -- Ignore -- this is output magic. */ + } else + if (strcmp(fmp->key, "INDEX") == 0) { + /* IGNORE -- Calculated Sequence # For Ouput*/ + } else + if (strcmp(fmp->key, "SHORTNAME") == 0) { + wpt->shortname = csv_stringtrim(s, "", 0); + } else + if (strcmp(fmp->key, "DESCRIPTION") == 0) { + wpt->description = csv_stringtrim(s, "", 0); + } else + if (strcmp(fmp->key, "NOTES") == 0) { + wpt->notes = csv_stringtrim(s, "", 0); + } else + if (strcmp(fmp->key, "URL") == 0) { + wpt->url = csv_stringtrim(s, "", 0); + } else + if (strcmp(fmp->key, "URL_LINK_TEXT") == 0) { + wpt->url_link_text = csv_stringtrim(s, "", 0); + } else + if (strcmp(fmp->key, "ICON_DESCR") == 0) { + wpt->icon_descr = csv_stringtrim(s, "", 0); + wpt->icon_descr_is_dynamic = 1; + } else + + /* LATITUDE CONVERSIONS**************************************************/ + if (strcmp(fmp->key, "LAT_DECIMAL") == 0) { + /* latitude as a pure decimal value */ + wpt->latitude = atof(s); + } else + if ((strcmp(fmp->key, "LAT_DECIMALDIR") == 0) || + (strcmp(fmp->key, "LAT_DIRDECIMAL") == 0)) { + /* latitude as a decimal with N/S in it. */ + wpt->latitude = decdir_to_dec(s); + } else + if (strcmp(fmp->key, "LAT_INT32DEG") == 0) { + /* latitude as a 32 bit integer offset */ + wpt->latitude = intdeg_to_dec(atof(s), 1); + } else + if ( strcmp(fmp->key, "LAT_HUMAN_READABLE") == 0) { + human_to_dec( s, &wpt->latitude, &wpt->longitude ); + } else + if ( strcmp(fmp->key, "LAT_NMEA") == 0) { + wpt->latitude = ddmm2degrees(wpt->latitude); + } else + /* LONGITUDE CONVERSIONS ***********************************************/ + if (strcmp(fmp->key, "LON_DECIMAL") == 0) { + /* longitude as a pure decimal value */ + wpt->longitude = atof(s); + } else + if ((strcmp(fmp->key, "LON_DECIMALDIR") == 0) || + (strcmp(fmp->key, "LON_DIRDECIMAL") == 0)) { + /* longitude as a decimal with N/S in it. */ + wpt->longitude = decdir_to_dec(s); + } else + if (strcmp(fmp->key, "LON_INT32DEG") == 0) { + /* longitude as a 32 bit integer offset */ + wpt->longitude = intdeg_to_dec(atof(s), 0); + } else + if ( strcmp(fmp->key, "LON_HUMAN_READABLE") == 0) { + human_to_dec( s, &wpt->latitude, &wpt->longitude ); + } else + if ( strcmp(fmp->key, "LON_NMEA") == 0) { + wpt->latitude = ddmm2degrees(wpt->longitude); + } else + /* LAT AND LON CONVERSIONS ********************************************/ + if ( strcmp(fmp->key, "LATLON_HUMAN_READABLE") == 0) { + human_to_dec( s, &wpt->latitude, &wpt->longitude ); + } else + /* DIRECTIONS **********************************************************/ + if (strcmp(fmp->key, "LAT_DIR") == 0) { + /* latitude N/S. Ignore on input for now */ + } else + if (strcmp(fmp->key, "LON_DIR") == 0) { + /* longitude E/W. Ingore on input for now */ + } else + + /* ALTITUDE CONVERSIONS ************************************************/ + if (strcmp(fmp->key, "ALT_FEET") == 0) { + /* altitude in feet as a decimal value */ + wpt->altitude = atof(s) * .3048; + } else + if (strcmp(fmp->key, "ALT_METERS") == 0) { + /* altitude in meters as a decimal value */ + wpt->altitude = atof(s); + } else + + /* TIME CONVERSIONS ***************************************************/ + if (strcmp(fmp->key, "EXCEL_TIME") == 0) { + /* Time as Excel Time */ + wpt->creation_time = EXCEL_TO_TIMET(atof(s)); + } else + if (strcmp(fmp->key, "TIMET_TIME") == 0) { + /* Time as time_t */ + wpt->creation_time = atol(s); + } else + + /* GEOCACHING STUFF ***************************************************/ + if (strcmp(fmp->key, "GEOCACHE_DIFF") == 0) { + /* Geocache Difficulty as an int */ + wpt->gc_data.diff = atof(s) * 10; + } else + if (strcmp(fmp->key, "GEOCACHE_TERR") == 0) { + /* Geocache Terrain as an int */ + wpt->gc_data.terr = atof(s) * 10; + } else + if (strcmp(fmp->key, "GEOCACHE_TYPE") == 0) { + /* Geocache Type */ + wpt->gc_data.type = gs_mktype(s); + } else + if (strcmp(fmp->key, "GEOCACHE_CONTAINER") == 0) { + wpt->gc_data.container = gs_mkcont(s); + } else + if ( strcmp( fmp->key, "PATH_DISTANCE_MILES") == 0) { + /* Ignored on input */ + } else + if ( strcmp( fmp->key, "PATH_DISTANCE_KM") == 0 ) { + /* Ignored on input */ + } else { + warning( MYNAME ": Unknown style directive: %s\n", fmp->key); + } +} + +/*****************************************************************************/ +/* xcsv_data_read() - read input file, parsing lines, fields and handling */ +/* any data conversion (the input meat) */ +/*****************************************************************************/ +void +xcsv_data_read(void) +{ + char buff[8192]; + char *s; + waypoint *wpt_tmp; + int linecount = 0; + queue *elem, *tmp; + field_map_t *fmp; + ogue_t *ogp; + + do { + linecount++; + memset(buff, '\0', sizeof(buff)); + fgets(buff, sizeof(buff), xcsv_file.xcsvfp); + + rtrim(buff); + + /* skip over x many lines on the top for the prologue... */ + if ((xcsv_file.prologue_lines) && ((linecount - 1) < + xcsv_file.prologue_lines)) { + continue; + } + + /* We should skip over epilogue lines also. Since we don't want to + * pre-read the file to know how many data lines we should be seeing, + * we take this cheap shot at the data and cross our fingers. + */ + + QUEUE_FOR_EACH(&xcsv_file.epilogue, elem, tmp) { + ogp = (ogue_t *) elem; + if (strncmp(buff, ogp->val, strlen(ogp->val)) == 0) { + buff[0] = '\0'; + break; + } + } + + if (strlen(buff)) { + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + + s = buff; + s = csv_lineparse(s, xcsv_file.field_delimiter, "", linecount); + + /* reset the ifield queue */ + elem = QUEUE_FIRST(&xcsv_file.ifield); + + /* now rip the line apart, advancing the queue for each tear + * off the beginning of buff since there's no index into queue. + */ + while (s) { + fmp = (field_map_t *) elem; + xcsv_parse_val(s, wpt_tmp, fmp); + + elem = QUEUE_NEXT(elem); + + if (elem == &xcsv_file.ifield) { + /* we've wrapped the queue. so stop parsing! */ + while (s) { + s=csv_lineparse(NULL, "\xff","",linecount); + } + break; + } + + s = csv_lineparse(NULL, xcsv_file.field_delimiter, "", + linecount); + } + waypt_add(wpt_tmp); + } + + } while (!feof(xcsv_file.xcsvfp)); +} + +static void +xcsv_resetpathlen() +{ + pathdist = 0; + oldlat = 999; + oldlon = 999; +} + +/*****************************************************************************/ +/* xcsv_waypt_pr() - write output file, handling output conversions */ +/* (the output meat) */ +/*****************************************************************************/ +static void +xcsv_waypt_pr(const waypoint *wpt) +{ + char buff[1024]; + char *shortname = NULL; + char *description = NULL; + char * anyname = NULL; + char * write_delimiter; + int i; + field_map_t *fmp; + queue *elem, *tmp; + + if ( oldlon < 900 ) { + pathdist += tomiles(gcdist(oldlat*M_PI/180,oldlon*M_PI/180, + wpt->latitude*M_PI/180,wpt->longitude*M_PI/180)); + } + oldlon = wpt->longitude; + oldlat = wpt->latitude; + + if (strcmp(xcsv_file.field_delimiter, "\\w") == 0) + write_delimiter = " "; + else + write_delimiter = xcsv_file.field_delimiter; + + if ((! wpt->shortname) || (global_opts.synthesize_shortnames)) { + if (wpt->description) { + if (global_opts.synthesize_shortnames) + shortname = mkshort(xcsv_file.mkshort_handle, wpt->description); + else + shortname = csv_stringclean(wpt->description, xcsv_file.badchars); + } else { + /* no shortname available -- let shortname default on output */ + } + } else{ + shortname = csv_stringclean(wpt->shortname, xcsv_file.badchars); + } + + if (! wpt->description) { + if (shortname) { + description = csv_stringclean(shortname, xcsv_file.badchars); + } else { + /* no description -- let description default on output */ + } + } else { + description = csv_stringclean(wpt->description, xcsv_file.badchars); + } + + if (prefer_shortnames) { + if (description) { + xfree(description); + } + description = shortname; + } + + if (description) { + char *odesc = description; + description = str_utf8_to_ascii(odesc); + xfree(odesc); + } + + i = 0; + QUEUE_FOR_EACH(xcsv_file.ofield, elem, tmp) { + fmp = (field_map_t *) elem; + + if (i != 0) + fprintf (xcsv_file.xcsvfp, write_delimiter); + + i++; + + if (strcmp(fmp->key, "IGNORE") == 0) { + /* IGNORE -- Write the char printf conversion */ + sprintf(buff, fmp->printfc, ""); + } else + if (strcmp(fmp->key, "INDEX") == 0) { + sprintf(buff, fmp->printfc, waypt_out_count + atoi(fmp->val)); + } else + if (strcmp(fmp->key, "CONSTANT") == 0) { + sprintf(buff, fmp->printfc, fmp->val); + } else + if (strcmp(fmp->key, "SHORTNAME") == 0) { + sprintf(buff, fmp->printfc, + (shortname && *shortname) ? shortname : fmp->val); + } else + if (strcmp(fmp->key, "ANYNAME") == 0) { + if (wpt->shortname) { + anyname = xstrdup(wpt->shortname); + } else + if (wpt->description) { + anyname = mkshort(xcsv_file.mkshort_handle, wpt->description); + } else + if (wpt->notes) { + anyname = xstrdup(wpt->notes); + } else + anyname = xstrdup(fmp->val); + + if ((anyname) && (global_opts.synthesize_shortnames)) { + anyname = xstrdup(shortname); + } + + sprintf(buff, fmp->printfc, anyname); + + xfree(anyname); + } else + if (strcmp(fmp->key, "DESCRIPTION") == 0) { + sprintf(buff, fmp->printfc, + (description && *description) ? description : fmp->val); + } else + if (strcmp(fmp->key, "NOTES") == 0) { + sprintf(buff, fmp->printfc, + (wpt->notes && *wpt->notes) ? wpt->notes : fmp->val); + } else + if (strcmp(fmp->key, "URL") == 0) { + int off = 0; + if (xcsv_urlbase) { + strcpy(buff, xcsv_urlbase); + off = strlen(xcsv_urlbase); + } + if (wpt->url) + sprintf(buff + off, fmp->printfc, wpt->url); + else + strcpy(buff, (fmp->val && *fmp->val) ? fmp->val : "\"\""); + } else + if (strcmp(fmp->key, "URL_LINK_TEXT") == 0) { + sprintf(buff, fmp->printfc, + (wpt->url_link_text && *wpt->url_link_text) ? wpt->url_link_text : fmp->val); + } else + if (strcmp(fmp->key, "ICON_DESCR") == 0) { + sprintf(buff, fmp->printfc, + (wpt->icon_descr && *wpt->icon_descr) ? + wpt->icon_descr : fmp->val); + } else + + /* LATITUDE CONVERSION***********************************************/ + if (strcmp(fmp->key, "LAT_DECIMAL") == 0) { + /* latitude as a pure decimal value */ + sprintf(buff, fmp->printfc, wpt->latitude); + } else + if (strcmp(fmp->key, "LAT_DECIMALDIR") == 0) { + /* latitude as a decimal value with N/S after it */ + sprintf(buff, fmp->printfc, fabs(wpt->latitude), + LAT_DIR(wpt->latitude)); + } else + if (strcmp(fmp->key, "LAT_DIRDECIMAL") == 0) { + /* latitude as a decimal value with N/S before it */ + sprintf(buff, fmp->printfc, + LAT_DIR(wpt->latitude), + fabs(wpt->latitude)); + } else + if (strcmp(fmp->key, "LAT_INT32DEG") == 0) { + /* latitude as an integer offset from 0 degrees */ + sprintf(buff, fmp->printfc, + dec_to_intdeg(wpt->latitude, 1)); + } else + if (strcmp(fmp->key, "LAT_HUMAN_READABLE") == 0) { + dec_to_human( buff, fmp->printfc, "SN", wpt->latitude ); + } else + if (strcmp(fmp->key, "LAT_NMEA") == 0) { + sprintf(buff, fmp->printfc, degrees2ddmm(wpt->latitude)); + } else + + /* LONGITUDE CONVERSIONS*********************************************/ + if (strcmp(fmp->key, "LON_DECIMAL") == 0) { + /* longitude as a pure decimal value */ + sprintf(buff, fmp->printfc, wpt->longitude); + } else + if (strcmp(fmp->key, "LON_DECIMALDIR") == 0) { + /* latitude as a decimal value with N/S after it */ + sprintf(buff, fmp->printfc, + fabs(wpt->longitude), + LON_DIR(wpt->longitude)); + } else + if (strcmp(fmp->key, "LON_DIRDECIMAL") == 0) { + /* latitude as a decimal value with N/S before it */ + sprintf(buff, fmp->printfc, + LON_DIR(wpt->longitude), + fabs(wpt->longitude)); + } else + if (strcmp(fmp->key, "LON_INT32DEG") == 0) { + /* longitudee as an integer offset from 0 degrees */ + sprintf(buff, fmp->printfc, + dec_to_intdeg(wpt->longitude, 0)); + } else + if (strcmp(fmp->key, "LON_HUMAN_READABLE") == 0) { + dec_to_human( buff, fmp->printfc, "WE", wpt->longitude ); + } else + if (strcmp(fmp->key, "LATLON_HUMAN_READABLE") == 0) { + dec_to_human( buff, fmp->printfc, "SN", wpt->latitude ); + if ( !isspace(buff[strlen(buff)])) strcat( buff, " " ); + dec_to_human( buff+strlen(buff), fmp->printfc, "WE", + wpt->longitude ); + } else + if (strcmp(fmp->key, "LON_NMEA") == 0) { + sprintf(buff, fmp->printfc, degrees2ddmm(wpt->longitude)); + } else + + /* DIRECTIONS *******************************************************/ + if (strcmp(fmp->key, "LAT_DIR") == 0) { + /* latitude N/S as a char */ + sprintf(buff, fmp->printfc, + LAT_DIR(wpt->latitude)); + } else + if (strcmp(fmp->key, "LON_DIR") == 0) { + /* longitude E/W as a char */ + sprintf(buff, fmp->printfc, + LON_DIR(wpt->longitude)); + } else + + /* ALTITUDE CONVERSIONS**********************************************/ + if (strcmp(fmp->key, "ALT_FEET") == 0) { + /* altitude in feet as a decimal value */ + sprintf(buff, fmp->printfc, + (wpt->altitude * 3.2808)); + } else + if (strcmp(fmp->key, "ALT_METERS") == 0) { + /* altitude in meters as a decimal value */ + sprintf(buff, fmp->printfc, + wpt->altitude); + } else + + /* DISTANCE CONVERSIONS**********************************************/ + if (strcmp(fmp->key, "PATH_DISTANCE_MILES") == 0) { + /* path (route/track) distance in miles */ + sprintf( buff, fmp->printfc, pathdist ); + } else + if (strcmp(fmp->key, "PATH_DISTANCE_KM") == 0) { + /* path (route/track) distance in */ + sprintf( buff, fmp->printfc, pathdist * 5280*12*2.54/100/1000 ); + } else + + /* TIME CONVERSIONS**************************************************/ + if (strcmp(fmp->key, "EXCEL_TIME") == 0) { + /* creation time as an excel (double) time */ + sprintf(buff, fmp->printfc, TIMET_TO_EXCEL(wpt->creation_time)); + } else + if (strcmp(fmp->key, "TIMET_TIME") == 0) { + /* time as a time_t variable */ + sprintf(buff, fmp->printfc, wpt->creation_time); + } else + + /* GEOCACHE STUFF **************************************************/ + if (strcmp(fmp->key, "GEOCACHE_DIFF") == 0) { + /* Geocache Difficulty as a double */ + sprintf(buff, fmp->printfc, wpt->gc_data.diff / 10.0); + } else + if (strcmp(fmp->key, "GEOCACHE_TERR") == 0) { + /* Geocache Terrain as a double */ + sprintf(buff, fmp->printfc, wpt->gc_data.terr / 10.0); + } else + if (strcmp(fmp->key, "GEOCACHE_CONTAINER") == 0) { + /* Geocache Container */ + sprintf(buff, fmp->printfc, gs_get_container(wpt->gc_data.container)); + } else + if (strcmp(fmp->key, "GEOCACHE_TYPE") == 0) { + /* Geocache Type */ + sprintf(buff, fmp->printfc, gs_get_cachetype(wpt->gc_data.type)); + } else { + /* this should probably never happen */ + } + + fprintf (xcsv_file.xcsvfp, "%s", buff); + + } + + fprintf (xcsv_file.xcsvfp, "%s", xcsv_file.record_delimiter); + + if (shortname) + xfree(shortname); + + if (description && description != shortname) + xfree(description); + + /* increment the index counter */ + waypt_out_count++; +} + +static void +xcsv_noop(const route_head *wp) +{ + /* no-op */ +} + +/*****************************************************************************/ +/* xcsv_data_write(void) - write prologues, spawn the output loop, and write */ +/* epilogues. */ +/*****************************************************************************/ +void +xcsv_data_write(void) +{ + queue *elem, *tmp; + ogue_t *ogp; + + /* reset the index counter */ + waypt_out_count = 0; + + /* output prologue lines, if any. */ + QUEUE_FOR_EACH(&xcsv_file.prologue, elem, tmp) { + char *ol; + ogp = (ogue_t *) elem; + + ol = strsub(ogp->val, "__FILE__", xcsv_file.fname); + + if (ol) { + fprintf(xcsv_file.xcsvfp, "%s", ol); + xfree(ol); + } else { + fprintf(xcsv_file.xcsvfp, "%s", ogp->val); + } + fprintf(xcsv_file.xcsvfp, "%s", xcsv_file.record_delimiter); + } + + waypt_disp_all(xcsv_waypt_pr); + route_disp_all(xcsv_resetpathlen,xcsv_noop,xcsv_waypt_pr); + track_disp_all(xcsv_resetpathlen,xcsv_noop,xcsv_waypt_pr); + + /* output epilogue lines, if any. */ + QUEUE_FOR_EACH(&xcsv_file.epilogue, elem, tmp) { + ogp = (ogue_t *) elem; + fprintf (xcsv_file.xcsvfp, "%s%s", ogp->val, xcsv_file.record_delimiter); + } +} + diff --git a/csv_util.h b/csv_util.h new file mode 100644 index 000000000..e1e12cb16 --- /dev/null +++ b/csv_util.h @@ -0,0 +1,131 @@ +/* + Copyright (C) 2002 Alex Mottram (geo_alexm at cox-internet.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +/* function prototypes */ + +char * +#ifndef DEBUG_MEM +csv_stringtrim(const char *string, const char *enclosure, int strip_max); +#else +CSV_STRINGTRIM(const char *string, const char *enclosure, int strip_max, DEBUG_PARAMS); +#define csv_stringtrim( s, e,m ) CSV_STRINGTRIM( s, e, m, __FILE__, __LINE__) +#endif + +char * +csv_lineparse(const char *stringstart, const char *delimited_by, const char *enclosed_in, const int line_no); + +char * +#ifndef DEBUG_MEM +csv_stringclean(const char *string, const char *chararray); +#else +CSV_STRINGCLEAN(const char *string, const char *chararray,DEBUG_PARAMS); +#define csv_stringclean(s,c) CSV_STRINGCLEAN(s,c,__FILE__,__LINE__) +#endif + +void +xcsv_data_read(void); + +void +xcsv_data_write(void); + +void +xcsv_file_init(void); + +void +xcsv_prologue_add(char *); + +void +xcsv_epilogue_add(char *); + +void +xcsv_ifield_add(char *, char *, char *); + +void +xcsv_ofield_add(char *, char *, char *); + +void +xcsv_destroy_style(void); + +/****************************************************************************/ +/* types required for various xcsv functions */ +/****************************************************************************/ + +/* something to map fields to waypts */ +typedef struct field_map { + queue Q; + char * key; + char * val; + char * printfc; +} field_map_t; + +/* a queuing struct for prologues / epilogues */ +typedef struct ogue { + queue Q; + char * val; +} ogue_t; + +/* something to map config file constants to chars */ +typedef struct char_map { + const char * key; + const char * chars; +} char_map_t; + +/* + * a type describing all the wonderful elements of xcsv files, in a + * nutshell. + */ +typedef struct { + int is_internal; /* bool - is internal (1) or parsed (0) */ + + int prologue_lines; /* # of lines to ignore at top of the file */ + int epilogue_lines; /* # of lines to ignore at bottom of file */ + + /* header lines for writing at the top of the file. */ + queue prologue; + + /* footer lines for writing at the bottom of the file. */ + queue epilogue; + + char * field_delimiter; /* comma, quote, etc... */ + char * record_delimiter; /* newline, c/r, etc... */ + + char * badchars; /* characters we never write to output */ + + queue ifield; /* input field mapping */ + queue * ofield; /* output field mapping */ + + int ifield_ct; /* actual # of ifields */ + int ofield_ct; /* actual # of ofields */ + + FILE * xcsvfp; /* ptr to current *open* data file */ + char * fname; /* ptr to filename of above. */ + + char * description; /* Description for help text */ + char * extension; /* preferred filename extension (for wrappers)*/ + + void * mkshort_handle; /* handle for mkshort() */ + ff_type type; /* format type for GUI wrappers. */ + +} xcsv_file_t; + + +/****************************************************************************/ +/* obligatory global struct */ +/****************************************************************************/ +xcsv_file_t xcsv_file; diff --git a/defs.h b/defs.h new file mode 100644 index 000000000..21fa18ae2 --- /dev/null +++ b/defs.h @@ -0,0 +1,530 @@ +/* + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#ifndef gpsbabel_defs_h_included +#define gpsbabel_defs_h_included +#include +#include +#include +#include +#include +#include +#include +#include "queue.h" + + +/* + * Amazingly, this constant is not specified in the standard... + */ +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +/* + * Snprintf is in SUS (so it's in most UNIX-like substance) and it's in + * C99 (albeit with slightly different semantics) but it isn't in C89. + * This tweaks allows us to use snprintf on the holdout. + */ +#if __WIN32__ +# define snprintf _snprintf +#endif + +/* + * Common definitions. There should be no protocol or file-specific + * data in this file. + */ +#define BASE_STRUCT(memberp, struct_type, member_name) \ + ((struct_type *)((char *)(memberp) - offsetof(struct_type, member_name))) + + +/* + * Define globally on which kind of data gpsbabel is working. + * Important for "file types" that are essentially a communication + * protocol for a receiver, like the Magellan serial data. + */ +typedef enum { + trkdata = 1 , + wptdata, + rtedata +} gpsdata_type; + +#define NOTHINGMASK 0 +#define WPTDATAMASK 1 +#define TRKDATAMASK 2 +#define RTEDATAMASK 4 + +/* mask objective testing */ +#define doing_nothing (global_opts.masked_objective == NOTHINGMASK) +#define doing_wpts ((global_opts.masked_objective & WPTDATAMASK) == WPTDATAMASK) +#define doing_trks ((global_opts.masked_objective & TRKDATAMASK) == TRKDATAMASK) +#define doing_rtes ((global_opts.masked_objective & RTEDATAMASK) == RTEDATAMASK) + +typedef struct { + int synthesize_shortnames; + int debug_level; + gpsdata_type objective; + unsigned int masked_objective; + int verbose_status; /* set by GUI wrappers for status */ + int no_smart_icons; +} global_options; + +extern global_options global_opts; +extern const char gpsbabel_version[]; + +/* + * Extended data if waypoint happens to represent a geocache. This is + * totally voluntary data... + */ + +typedef enum { + gt_unknown = 0 , + gt_traditional, + gt_multi, + gt_virtual, + gt_letterbox, + gt_event, + gt_suprise, + gt_webcam +} geocache_type; + +typedef enum { + gc_unknown = 0, + gc_micro, + gc_other, + gc_regular, + gc_large, + gc_virtual, + gc_small +} geocache_container; + +typedef struct { + int is_html; + char *utfstring; +} utf_string; + +typedef struct { + geocache_type type; + geocache_container container; + int id; /* The decimal cache number */ + int diff; /* (multiplied by ten internally) */ + int terr; /* (likewise) */ + time_t exported; + char *hint; /* all these UTF8, XML entities removed, May be not HTML. */ + utf_string desc_short; + utf_string desc_long; +} geocache_data ; + +typedef struct xml_tag { + char *tagname; + char *cdata; + int cdatalen; + char *parentcdata; + int parentcdatalen; + char **attributes; + struct xml_tag *parent; + struct xml_tag *sibling; + struct xml_tag *child; +} xml_tag ; + +/* + * This is a waypoint, as stored in the GPSR. It tries to not + * cater to any specific model or protocol. Anything that needs to + * be truncated, edited, or otherwise trimmed should be done on the + * way to the target. + */ +typedef struct { + queue Q; /* Master waypoint q. Not for use + by modules. */ + + double latitude; /* Degrees */ + double longitude; /* Degrees */ + double altitude; /* Meters. */ + + /* + * The "thickness" of a waypoint; adds an element of 3D. Can be + * used to construct rudimentary polygons for, say, airspace + * definitions. The units are meters. + */ + double depth; + + /* + * An alarm trigger value that can be considered to be a circle + * surrounding a waypoint (or cylinder if depth is also defined). + * The units are meters. + */ + double proximity; + + /* shortname is a waypoint name as stored in receiver. It should + * strive to be, well, short, and unique. Enforcing length and + * character restrictions is the job of the output. A typical + * minimum length for shortname is 6 characters for NMEA units, + * 8 for Magellan and 10 for Vista. These are only guidelines. + */ + char *shortname; + /* + * description is typically a human readable description of the + * waypoint. It may be used as a comment field in some receivers. + * These are probably under 40 bytes, but that's only a guideline. + */ + char *description; + /* + * notes are relatively long - over 100 characters - prose associated + * with the above. Unlike shortname and description, these are never + * used to compute anything else and are strictly "passed through". + * Few formats support this. + */ + char *notes; + char *url; + char *url_link_text; + int icon_descr_is_dynamic; + const char *icon_descr; + time_t creation_time; /* standardized in UTC/GMT */ + int centiseconds; /* Optional hundredths of a second. */ + + /* + * route priority is for use by the simplify filter. If we have + * some reason to believe that the route point is more important, + * we can give it a higher (numerically; 0 is the lowest) priority. + * This causes it to be removed last. + * This is currently used by the saroute input filter to give named + * waypoints (representing turns) a higher priority. + */ + int route_priority; + + geocache_data gc_data; + xml_tag *gpx_extras; + void *extra_data; /* Extra data added by, say, a filter. */ +} waypoint; + +typedef struct { + queue Q; /* Link onto parent list. */ + queue waypoint_list; /* List of child waypoints */ + char *rte_name; + char *rte_desc; + int rte_num; + int rte_waypt_ct; /* # waypoints in waypoint list */ +} route_head; + +/* + * Bounding box information. + */ +typedef struct { + double max_lat; + double max_lon; + double min_lat; + double min_lon; +} bounds; + +typedef void (*ff_init) (char const *); +typedef void (*ff_deinit) (void); +typedef void (*ff_read) (void); +typedef void (*ff_write) (void); +typedef void (*ff_exit) (void); + +#ifndef DEBUG_MEM +char * get_option(const char *iarglist, const char *argname); +#else +#define DEBUG_PARAMS const char *file, const int line +char *GET_OPTION(const char *iarglist, const char *argname, DEBUG_PARAMS); +#define get_option(iarglist, argname) GET_OPTION(iarglist, argname, __FILE__, __LINE__) +#endif + +typedef void (*filter_init) (char const *); +typedef void (*filter_process) (void); +typedef void (*filter_deinit) (void); +typedef void (*filter_exit) (void); + +typedef void (*waypt_cb) (const waypoint *); +typedef void (*route_hdr)(const route_head *); +typedef void (*route_trl)(const route_head *); +void waypt_add (waypoint *); +waypoint * waypt_dupe (const waypoint *); +waypoint * waypt_new(void); +void waypt_del (waypoint *); +void waypt_free (waypoint *); +void waypt_disp_all(waypt_cb); +void waypt_compute_bounds(bounds *); +void waypt_flush(queue *); +void waypt_flush_all(void); +unsigned int waypt_count(void); +void free_gpx_extras (xml_tag * tag); +void xcsv_setup_internal_style(const char *style_buf); +void xcsv_read_internal_style(const char *style_buf); +waypoint * find_waypt_by_name(const char *name); + +route_head *route_head_alloc(void); +void route_add (waypoint *); +void route_add_wpt(route_head *rte, waypoint *wpt); +void route_del_wpt(route_head *rte, waypoint *wpt); +void route_add_head(route_head *rte); +void route_del_head(route_head *rte); +void route_reverse(const route_head *rte_hd); +void track_add_head(route_head *rte); +void track_del_head(route_head *rte); +void route_disp_all(route_hdr, route_trl, waypt_cb); +void track_disp_all(route_hdr, route_trl, waypt_cb); +void route_free (route_head *); +void route_flush( queue *); +void route_flush_all(void); +unsigned int route_waypt_count(void); +unsigned int route_count(void); +unsigned int track_count(void); + +/* + * All shortname functions take a shortname handle as the first arg. + * This is an opaque pointer. Callers must not fondle the contents of it. + */ +#ifndef DEBUG_MEM +char *mkshort (void *, const char *); +void *mkshort_new_handle(void); +#else +char *MKSHORT(void *, const char *, DEBUG_PARAMS); +void *MKSHORT_NEW_HANDLE(DEBUG_PARAMS); +#define mkshort( a, b) MKSHORT(a,b,__FILE__, __LINE__) +#define mkshort_new_handle() MKSHORT_NEW_HANDLE(__FILE__,__LINE__) +#endif +void mkshort_del_handle(void *h); +void setshort_length(void *, int n); +void setshort_badchars(void *, const char *); +void setshort_mustupper(void *, int n); +void setshort_mustuniq(void *, int n); +void setshort_whitespace_ok(void *, int n); + +/* + * Vmem flags values. + */ +#define VMFL_NOZERO (1 << 0) +typedef struct vmem { + void *mem; /* visible memory object */ + size_t size; /* allocated size of object */ +} vmem_t; +vmem_t vmem_alloc(size_t, int flags); +void vmem_free(vmem_t*); +void vmem_realloc(vmem_t*, size_t); + + +#define ARGTYPE_UNKNOWN 0 +#define ARGTYPE_INT 0x00000001 +#define ARGTYPE_FLOAT 0x00000002 +#define ARGTYPE_STRING 0x00000003 +#define ARGTYPE_BOOL 0x00000004 +#define ARGTYPE_FILE 0x00000005 +#define ARGTYPE_OUTFILE 0x00000006 +#define ARGTYPE_REQUIRED 0x40000000 +#define ARGTYPE_HIDDEN 0x20000000 + +#define ARGTYPE_TYPEMASK 0x00000fff +#define ARGTYPE_FLAGMASK 0xfffff000 + +typedef struct arglist { + char *argstring; + char **argval; + char *helpstring; + char *defaultvalue; + long argtype; +} arglist_t; + +typedef enum { + ff_type_file = 1, /* normal format: useful to a GUI. */ + ff_type_internal, /* fmt not useful with default options */ + ff_type_serial, /* format describes a serial protoco (GUI can display port names) */ +} ff_type; + +/* + * Describe the file format to the caller. + */ +typedef struct ff_vecs { + ff_type type; + ff_init rd_init; + ff_init wr_init; + ff_deinit rd_deinit; + ff_deinit wr_deinit; + ff_read read; + ff_write write; + ff_exit exit; + arglist_t *args; +} ff_vecs_t; + +typedef struct style_vecs { + const char *name; + const char *style_buf; +} style_vecs_t; +extern style_vecs_t style_list[]; + +typedef struct filter_vecs { + filter_init f_init; + filter_process f_process; + filter_deinit f_deinit; + filter_exit f_exit; + arglist_t *args; +} filter_vecs_t; + +void waypt_init(void); +void route_init(void); +void waypt_disp(const waypoint *); +void fatal(const char *, ...) +#if __GNUC__ + __attribute__ ((__format__ (__printf__, 1, 2))) +#endif + ; +void warning(const char *, ...) +#if __GNUC__ + __attribute__ ((__format__ (__printf__, 1, 2))) +#endif + ; +ff_vecs_t *find_vec(char *, char **); +void disp_vecs(void); +void exit_vecs(void); +void disp_formats(int version); +void printposn(double c, int is_lat); + +filter_vecs_t * find_filter_vec(char *, char **); +void free_filter_vec(filter_vecs_t *); +void disp_filters(int version); +void disp_filter_vecs(void); +void exit_filter_vecs(void); + +#ifndef DEBUG_MEM +void *xcalloc(size_t nmemb, size_t size); +void *xmalloc(size_t size); +void *xrealloc(void *p, size_t s); +void xfree(void *mem); +char *xstrdup(const char *s); +char *xstrndup(const char *s, size_t n); +char *xstrndupt(const char *s, size_t n); +char *xstrappend(char *src, const char *addon); +#define xxcalloc(nmemb, size, file, line) xcalloc(nmemb, size) +#define xxmalloc(size, file, line) xmalloc(size) +#define xxrealloc(p, s, file, line) xrealloc(p,s) +#define xxfree(mem, file, line) xfree(mem) +#define xxstrdup(s, file, line) xstrdup(s) +#define xxstrappend(src, addon, file, line) xstrappend(src, addon) +#else /* DEBUG_MEM */ +void *XCALLOC(size_t nmemb, size_t size, DEBUG_PARAMS ); +void *XMALLOC(size_t size, DEBUG_PARAMS ); +void *XREALLOC(void *p, size_t s, DEBUG_PARAMS ); +void XFREE(void *mem, DEBUG_PARAMS ); +char *XSTRDUP(const char *s, DEBUG_PARAMS ); +char *XSTRNDUP(const char *src, size_t size, DEBUG_PARAMS ); +char *XSTRNDUPT(const char *src, size_t size, DEBUG_PARAMS ); +char *XSTRAPPEND(char *src, const char *addon, DEBUG_PARAMS ); +void debug_mem_open(); +void debug_mem_output( char *format, ... ); +void debug_mem_close(); +#define xcalloc(nmemb, size) XCALLOC(nmemb, size, __FILE__, __LINE__) +#define xmalloc(size) XMALLOC(size, __FILE__, __LINE__) +#define xrealloc(p, s) XREALLOC(p,s,__FILE__,__LINE__) +#define xfree(mem) XFREE(mem, __FILE__, __LINE__) +#define xstrdup(s) XSTRDUP(s, __FILE__, __LINE__) +#define xstrndup(s, z) XSTRNDUP(s, z, __FILE__, __LINE__) +#define xstrndupt(s, z) XSTRNDUPT(s, z, __FILE__, __LINE__) +#define xstrappend(src,addon) XSTRAPPEND(src, addon, __FILE__, __LINE__) +#define xxcalloc XCALLOC +#define xxmalloc XMALLOC +#define xxrealloc XREALLOC +#define xxfree XFREE +#define xxstrdup XSTRDUP +#define xxstrndupt XSTRNDUPT +#define xxstrappend XSTRAPPEND +#endif /* DEBUG_MEM */ + +FILE *xfopen(const char *fname, const char *type, const char *errtxt); +void xfprintf(const char *errtxt, FILE *stream, const char *format, ...); +void xfputs(const char *errtxt, const char *s, FILE *stream); + +int case_ignore_strcmp(const char *s1, const char *s2); + +char *strsub(char *s, char *search, char *replace); +void rtrim(char *s); +signed int get_tz_offset(void); +time_t current_time(void); +signed int month_lookup(const char *m); +const char *get_cache_icon(const waypoint *waypointp); +char * xml_entitize(const char * str); +char * html_entitize(const char * str); +char * strip_html(const utf_string*); +char * strip_nastyhtml(const char * in); +char * str_utf8_to_cp1252( const char * str ); +char * str_utf8_to_ascii( const char * str ); + +/* this lives in gpx.c */ +time_t xml_parse_time( char *cdatastr ); + +xml_tag *xml_findfirst( xml_tag *root, char *tagname ); +xml_tag *xml_findnext( xml_tag *root, xml_tag *cur, char *tagname ); +char *xml_attribute( xml_tag *tag, char *attrname ); + +char * rot13( const char *str ); + +/* + * PalmOS records like fixed-point numbers, which should be rounded + * to deal with possible floating-point representation errors. + */ + +signed int si_round( double d ); + +/* + * Data types for Palm/OS files. + */ +typedef struct { + unsigned char data[4]; +} pdb_32; + +typedef struct { + unsigned char data[2]; +} pdb_16; + +typedef struct { + unsigned char data[8]; +} pdb_double; + +/* + * Protypes for Endianness helpers. + */ + +signed int be_read16(void *p); +signed int be_read32(void *p); +signed int le_read16(void *p); +signed int le_read32(void *p); +void le_read64(void *dest, const void *src); +void be_write16(void *pp, unsigned i); +void be_write32(void *pp, unsigned i); +void le_write16(void *pp, unsigned i); +void le_write32(void *pp, unsigned i); +double pdb_read_double(void *p); +void pdb_write_double(void *pp, double d); + +/* + * Prototypes for generic conversion routines (util.c). + */ + +double ddmm2degrees(double ddmm_val); +double degrees2ddmm(double deg_val); + +/* + * From util_crc.c + */ +unsigned long get_crc32(const void * data, int datalen); + +/* + * A constant for unknown altitude. It's tempting to just use zero + * but that's not very nice for the folks near sea level. + */ +#define unknown_alt -99999999.0 + +#endif /* gpsbabel_defs_h_included */ diff --git a/delgpl.c b/delgpl.c new file mode 100644 index 000000000..dd0146975 --- /dev/null +++ b/delgpl.c @@ -0,0 +1,124 @@ +/* + DeLorme GPL Track Format. + + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include + +#include "defs.h" + +#define MYNAME "GPL" + +typedef struct gpl_point { + unsigned int status; + unsigned int dummy1; + double lat; + double lon; + double alt; /* in feet */ + double heading; + double speed; /* mps */ + unsigned int tm; + unsigned int dummy3; +} gpl_point_t; + +static FILE *gplfile_in; +static FILE *gplfile_out; + +static void +gpl_rd_init(const char *fname) +{ + gplfile_in = xfopen(fname, "rb", MYNAME); + if (sizeof(struct gpl_point) != 56) { + fatal(MYNAME, ": gpl_point is %d instead of 56.\n", + sizeof(struct gpl_point)); + } +} + +static void +gpl_read(void) +{ + waypoint *wpt_tmp; + route_head *track_head; + int br; + gpl_point_t gp; + double alt_feet; + + track_head = route_head_alloc(); + track_add_head(track_head); + + while (fread(&gp, sizeof(gp), 1, gplfile_in) > 0) { + wpt_tmp = waypt_new(); + le_read64(&wpt_tmp->latitude, &gp.lat); + le_read64(&wpt_tmp->longitude, &gp.lon); + le_read64(&alt_feet, &gp.alt); + wpt_tmp->altitude = alt_feet * .3048; + wpt_tmp->creation_time = le_read32(&gp.tm); + route_add_wpt(track_head, wpt_tmp); + } +} + + +static void +gpl_rd_deinit(void) +{ + fclose(gplfile_in); +} + +static void +gpl_wr_init(const char *fname) +{ + gplfile_out = xfopen(fname, "wb", MYNAME); +} + +static void +gpl_wr_deinit(void) +{ + fclose(gplfile_out); +} + +static void +gpl_trackpt(const waypoint *wpt) +{ + double alt_feet = wpt->altitude / .3048; + gpl_point_t gp = {0}; + le_read64(&gp.lat, &wpt->latitude); + le_read64(&gp.lon, &wpt->longitude); + le_read64(&gp.alt, &alt_feet); + le_write32(&gp.tm, wpt->creation_time); + + fwrite(&gp, sizeof(gp), 1, gplfile_out); +} + +static void +gpl_write(void) +{ + track_disp_all(NULL, NULL, gpl_trackpt); +} + +ff_vecs_t gpl_vecs = { + ff_type_file, + gpl_rd_init, + gpl_wr_init, + gpl_rd_deinit, + gpl_wr_deinit, + gpl_read, + gpl_write, + NULL +}; diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 000000000..acda41108 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,7 @@ +doc.dvi: doc.tex + latex doc.tex + latex doc.tex + latex doc.tex + +clean: + rm -f *.toc *.aux *.dvi *.log diff --git a/doc/babelfront2.eps b/doc/babelfront2.eps new file mode 100644 index 000000000..478d74241 --- /dev/null +++ b/doc/babelfront2.eps @@ -0,0 +1,19937 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (babelfront2.eps) +%%CreationDate: (Tue Jun 17 21:11:51 2003) +%%BoundingBox: 0 0 563 419 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Pages: 1 +%%EndComments + +%%BeginDefaults +%%PageOrientation: Portrait +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 eq + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 eq + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 eq + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 eq + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-none or 1-RunlengthEncoded. + % hex color packets. + % + gsave + /buffer 512 string def + /byte 1 string def + /color_packet 3 string def + /pixels 768 string def + + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Times-Roman findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse + grestore +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 0 563 419 +userdict begin +DisplayImage +0 0 +563 419 +12.000000 +563 419 +0 +0 +e6f5ffd9f2ffdbffff000f20c5ffff0652b00043d5065dff004aed004ee30052d40056ce +0057d60057dc0056e70056e1075cdb0a5dd30a5dd30b5ed40a5fd40a5fd4095ed3095ed3 +075ed2075ed2075ed2065dd1065dd1065dd1035cd0025cd6005de0005de5005de5005de3 +005de3005ee0005ee0005fdc0060da0061d70061d70061d30062d30062d10062d10062d3 +0060d70060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +0060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d80060d8 +005ed6005ed6005ed6005ed6005ed6005ed6005ed6005ed6005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd8 +005dd8005dd8005dd8005dd8005dd8005dd8005dd8005dd1085fc8085bc50659d30658e0 +0253eb004feb0052eb035ae8045ed90460cf0760c8065ec8085bd10758dd0a54eb0257f2 +0060f4005ae90061f40069ff005cf8005eef0068e50061d60261e30355dd1057e3004ed0 +0061d3006cd90047c50347d00050e70052ec0052e90052e9004deb004ce3004cd6004ec6 +004fb1005cc0035fda004fd90039cc0949cdc3ffffd1ffffe9ffffe4ebfffbffffdaf0ff +daf6ffc7f1ff2c64950347921e6dd4146af3005af31d7aff1e7eff2282ff2789ff2b8dff +2d91ff2f91ff3192ff3894ff3a94ff3b95ff3b95ff3b95ff3996ff3a94ff3895ff3895ff +3895ff3794ff3794ff3794ff3693ff3594ff3593ff3593ff3593ff3593ff3593ff3593ff +3594ff3394ff3395ff3296ff3296ff3296ff3296ff3097ff3098ff3097ff3297ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff3395ff +3395ff3395ff3395ff3395ff3395ff3395ff3595ff2f8cff3a94ff3c95ff3893ff3c97ff +44a0ff3e9aff2f8cff3493ff3494ff3594ff3694ff3693ff3790ff388eff348fff2a92ff +2998ff2796ff2691ff2a90ff268dff2091ff2a98ff3597ff3a8eff4b94ff3289ff168eff +2196ff358aff4d97ff378fff3192ff3092ff3090ff328cff348aff3389ff328cff389aff +258af61c79fc2779ff3076ff1c61ed0042a9003a83e4fffff0fefff8ffffdcfcffe0ffff +1a45a41c50c6175bd6095cd63390ff0d6fec1677ff1878ff1d7cff2181ff2689fe298efa +2c91fd2c91ff2890ff278fff2990ff2990ff2990ff2890ff288fff268eff278fff278fff +278fff268eff268eff268eff258dff268dff2a8dff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2a8dff2a8dff2a8dff2a8dff2a8dff2a8dff2a8dff2a8dff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff2b8cff +2b8cff2b8cff2b8cff2b8cff2b8cff2a8bff3196ff268dff208aff1e8bff1e8cff1c8aff +1f8cff2591ff2590ff2590ff2791ff2792ff2793ff2794ff2993ff2b93ff2a8afa3894ff +2b89fb2784fd3792ff3193ff1d8dfd2393ff268aff1f78fa3083ff2c8bff1897ff1c9eff +2688ff2680fa248bf2218eed208ef0218bfb2487ff2582ff2580ff2581ff2080f91173f2 +2782ff2076ff0754ff1563ff0d61dd2269c3163c7aebfffff2ffffc6f0ff0e3b7f1946c5 +0e45dd2068f81067e8004fb90c75e20268f00466ff0866ff0b6afc0f6fe81173e21074e4 +0d74eb0676f60476fb0676fe0676fc0575fd0575fb0474fc0473f90573fc0574fa0573fc +0574fa0472fb0473f90371fa0670f70b70f20e6ff10e6ff10e6ff10e6ff10e6ff20e6ff2 +0e6ff40d6ff40d6ff60d6ff80d6ff80d6ff80d6ef90e6ef90e6ef80e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef8 +0e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60e6ef80e6ef60b6bf50b6bf30b6bf5 +0b6bf30b6bf50b6bf30b6bf50b6bf50b6bf50b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf60b6bf50b6bf6 +0b6bf50b6bf60b6bf50b6bf6086bfd0064ff006dff0577fc067bed0176e00071db0070ea +0473f90068fa0067fe0069f8006bf1006deb006ee8006ee8036ce20960d11d6ddc2175e9 +1b6fe91366e80865e8006de70274f0076aec065ee41365ed0965ea0060d80060d9005ee3 +085fe00660d00562ca0662d10461da065dea055bf0045aef045be80962e4004ed40356f0 +0856fe115cff0653f91f71f80044ae1640922a447de6fcffd5ffff23599f0b42c11456eb +0046d00464df016dd20059c50066f70264ff0463ff0765ff0869ee0869eb0867f70468fa +006ef8006ff60070f90070f7006ef8006ef5006cf6006bf3006cf6006cf4006bf6006af3 +0069f50069f30068f40068f00168e90467e60467e80467e80467e90466eb0466ed0466ef +0565f00564f20564f40564f60563f70563f90762f90762f70763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20763f40763f20763f40763f2 +0763f40763f20763f40763f20763f40763f20763f40763f20561f20561f00561f20561f0 +0561f20561f00561f20561f20561f20561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40561f20561f40561f20561f40561f20561f40561f20561f40561f2 +0561f40561f20561f40063f40060ee0273f70173e30062c50060c00570d80b71ed0063ec +0667f60667f60469ef036aeb026beb006af20068ff0466fb1466f0044ed30653dd105fef +0e5cf20f68ff0274ff0060f70060f5085aee0f57ea0f60ef006af10069f0085dec0748e0 +184aeb1b48ec194aed154bf3104cfc0b4cfc074ef40751e80b55d8135cdc0043d20039d5 +1354fa0038d70041ca0d49c10d37a5001979e4feff002b710e45a00742ca1057ef004fdc +0061e00056c50473e90060f4005eff005eff0061fa0264eb0365ec0361fe0063ff0067f6 +006af0006af2006af00068f10068ee0064ee0065ec0064ee0064ec0062ed0062eb0060ec +0061ea0060ec0060e90060e40060e20060e2005fe4005fe6005fe8005ee9005eeb005ded +005def005cf2005bf4005af6005af6005af8005af6005bf0005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef005cef +005cef005cef005cef005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0005bf0 +005bf0005bf0015bed035de7005ad4065fc3116bc1166cbf1162bd0f58c91257d61457dc +1358d9125ad00f5bc90c5ccb085bd30759e30a56e7195de40f4fd3165ae32063ef1251de +004adb0057ed0059eb0048d02457d61e46bf1540b30f4dba0e4db71e49b9243db42a33bc +2e31be2d34b92836bb1e38c0183bbd143cb5133ea710388f1a3f97183fa81039b50021b4 +1e51e80035c10133ba0024aa1938b5011d880c39b6002cb10642d80248e40051e4005be6 +005ce00054da0061f50061f80063f30066ee0168e80269ec0268fb0267fd0168f30269ec +0268ee0168eb0166ec0264e90262ea0162e70260e8035fe6035de7035de5055ce7045ce4 +055be6025ce6005de7005ee7005ee7005de8005de8005cea005cec005cee005aef005af1 +005af10059f30059f50059f50058f70059f5005aef005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee005aee +005aee005aee005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef005aef +005aef0856ea0a42d5426ff08cbaffccf8ffdbffffdcffffdef9ffe3faffe4f8ffe4f9ff +e2fcffdfffffdbffffd7ffffd5feffd1fdffc7f6ffcfffffcfffffbeedff90b7ff3665d1 +0045bb2062d0334ea5b9bafdfbeafffff3fffff7fff8ecffffeafffff1fffff1fffff2ff +fff3fffff6fffff9fffffbfffffdfffffdfffffcf8fffafffdf7ffcad0ff1c33a50325ad +0932c20932c81236d2000ea400199b0029c30022bd0c43e40246e50048e2004fe30065f5 +0060ee0061f10063ef0065e90067e70068e70068ea0066f50065f60063ec0263e80263e8 +0361e70260e6025ee5025ce4035be30258e10457e10356e00456e00555e00653df0653df +0255e10056e50057e90057e90057e90056e90056e90055ea0055ea0055ec0054ec0054ec +0054ec0054ec0053ee0053ee0054ec0054e90055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e70055e7 +0055e70055e70055e70055e70055e70053e50053e50053e50053e50053e50053e50053e5 +0053e50053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +0053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e70053e7 +034fe02251db8fb2ffc3e5ff90b1f6637db86c81c0737fd35b63c5656ad2626acd606cc2 +5c6eb8576eb2536eb3506cbf4a6cc64371d3376bd11748ae527cdec3e1ff96bbff1958c1 +1348a6b5baf2fedffed8a4b0b27676bb8382b87d77ba746ab97163b07160b0725bb5714e +b27149aa734ca6724aa47146a86e40ae6834a05c379b6563f4d8feb6baff1731aa0930bb +0029c1001bba0526bf000f960018b7052dcb0839de0140e5004ced0054ec0058e70061e8 +0061e6006bed0055d8036bee0772f6005fe70371fc005dea0057e20966f1015ee90054e0 +025ce8065dea0055e20156e40457e50455e4004fdf0b57e80b57e8024dde0651e20452e6 +004be20058f1004ce50054eb015af20050e80056ee0056ee0056eb0055eb0055ea0055ea +0055ea0055ea0055ea0056e80056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e60056e6 +0056e60056e60056e60056e60053e30053e30053e30053e30053e30053e30053e30053e3 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e5 +0053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50053e50052d9 +0e50c1c5fdff6ba2f28cc1ff85b2f686adfa7d9efd6d89f4758ffd7691fc6c8aea6e90ea +6589e75980e55f86fd507ef84481f63a7dee2f71e12a61c6274da2d6ffff0b53c2124caf +f7f9ffc198a6e9a9a0eda08ce89b89efa18bd98668dd886bdc8773e08572e37a5ce67a54 +dd7751ea845cd0653be97343ea632bdd5d2ebc5743804355fef5ff122f950335b20033c1 +0024b90526b3000f8a0019b4092dc90939d7053fde044de70054e50056e2005fe4005fe4 +0060e20369e9005ede005cde0066ee0060ef0061f20666f8005cec0057e80864f50059eb +025cee045def0d63f6085cf00053e70456ea004fe4004ee40553e9014fe50959f00255f1 +085ffc0459f40052ed0051ea0156ef0459f00050e70055ea0055ea0055e80055e60055e6 +0056e40056e40056e40056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30056e40057e30056e40057e30056e40057e30056e40057e30056e4 +0057e30056e40057e30054e20055e10054e20055e10054e20055e10054e20054e20054e2 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40054e20053e4 +0054e20053e40054e20053e40054e20053e40054e20053e40054e20053e40254d2155ab5 +c9ffff629ce57db2ff81afff89b1ff7fa5ff7899ff6689e7779bf1648ad56289d46d96e8 +638beb5d85f75785ff407ef9367bf42e6fe52b60c82c4c9fd8ffff0a51c71248b2fff7ff +bf8d90fbaf98ffb193f89c85da7e65f59b78e58866e6826bd5654fff9372f4734ced7552 +e16a48fa7b58ef643bfb5928f05328cd503a8c3e4bfff4ff1630910535b50031c20024b5 +0626ad001085001aab092fbe0d3bcc0843cf0750d30456d60057da035de50e68f4025ce6 +0965e20562d90563d70865e6005af30965ff005efa0055ee0058f10f71ff0056ef005bf5 +0055f00051ec0056f20050ec055efa0054f00052ef055cf9004dea0053ee0253ed0043dd +004ee70958f10352eb004ee5004bdf0051e50055e60055e60055e40055e30055e30055e3 +0055e30055e30055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e10055e30056e1 +0055e30056e10055e30056e10055e30056e10055e30056e10055e30056e30055e30056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40056e30055e40056e3 +0055e40056e30055e40056e30055e40056e30055e40056e30055e40956cc1a559bd8ffff +6690da81a6ff8faeff89a5ff728ef27894e899b7f3d8f8ffdeffffddffffe4ffffc9e7ff +8ba8ee5678d24274e73c72f0376ae0365bc33a4796e6faff114bc81742b2ffedffc58482 +f39c81ff9a7ce98273ffa293cd7359e38667f6876bf27353dc522bfb764dde6c4ae57b61 +cf654fd55941f05737eb5135cb4f438b3c4ffff2ff192e990c31be042cca0021ba0924af +000e86001bb70830c60c3dca0945ca0a51cf0756d50355dd0a5be80858e30b5adb0354c0 +0f62c21467c70b5cc80f5de50355e9005ef40466fd005bf40264fb0051ea0463fb005af4 +005af2015ef9025ff8005af60052eb0051ed0059f3035cf8055af31462f80047da054fe2 +0551e3004adc0450e20554e51160f00354e30354e30255e30255e30255e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e30055e3 +0055e30054e20054e20054e20054e20054e20054e20054e20054e20054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e30054e3 +0054e30054e30054e30054e30054e30054e30054e30054e30954c91b5191dbffff6084d0 +7b9cfb8da9ff7894ff6784e08fb0f7d2f2ffe3ffffceedffc2dffddef8ffe9ffffd4eaff +81a0e33d6ddb376eed3668e1395cc23d478fe8f9ff0f4aca1441b4fff3ffbc786fed9474 +f5916ffe988cffaea6ffead6d6866bd2664ae36646e25a32f87a52c66545b46048ffe8d8 +ffaa9be45640e4513dc950478a3b50fff1ff1d2d9e142ec90928d1031fc00a23b4000d8c +0017da052ee2083dd70645d00951d90853e00851eb1058eb0c52d45ea5ffb1f6ffc8ffff +c8ffffaff1ff6babff1f66d2004fd30662f10058e90561f00864f50964f3004ee0015ceb +004ddf015ceb0050e20059e90058ea004fdf0059eb004ad8054ed81056dc195fe50c54dc +0850d8125be50a56e00047d10653df0454e10354e30254e40254e60254e60054e80055e6 +0055e60055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e40055e4 +0054e30054e30054e30054e30054e30054e30054e30054e30054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e50054e5 +0054e50054e50054e50054e50054e50054e50054e50953cc265aa3daffff5279c66a8fe8 +789ffc648de56e9ae3c0edffdbffff9dc3ff5a7acf4f6ac16a81d1b9d1ffeaffffb4d9ff +2e6dd7266fef2a6ce42f61c4364b8ce1fdff054ece0b47b9fff1ffbe8371db9066dd885f +e28a7effe8e4ffe3d0fff2dad17963dd6f56e46f4cc15934a25b3dfff1daffe0d2ffe9da +d55740de533cc65243883b4bfff2ff212ea0192dce0c25da051dc80a21bd000b95001ae2 +0030e80541d70448d10951e40952ed0b51f11557e92568d1bdfcffc2fcff063978002971 +b5e4ffcfffff5590d61d66d51063e50659dd0457d90f62e60154d60050d41164e60b5ee2 +0c5fe10053d70659db0657dc0052d40b5ce10d5ada084ec81456d00348c10e52cd165bda +054ccc0851d40e58df0753dd0653e10453e40353e60253ea0253eb0053ed0054eb0054ea +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e8 +0054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80054e80052e6 +0052e60052e60052e60052e60052e60052e60052e60052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e80052e8 +0052e80052e80052e80052e80052e80052e80a51d12558abdaffff5478d6668df66f9aff +5a88e66296e2b0e4ffbcebff6691f04969e0536de8455ac58196e5e0f6ffc9eeff266ad9 +1e6ef7256cec2c61c9364b8ee1fcff064ed40d48befff3ffae6d57de8d5ee58c60d67a6f +d0807ffff3e3fff4e1ffeee1bf7262c1674cb96646fff1d6ffe7d0fff1e3ab5846d85134 +e55030ce50378b3b3efff5ff1d349c1432d00727da021ec80922bd000b950020d20036d8 +0145ca014bce074fef0a51fb0c50f3195ada94d5ffc9ffff76a3e4294ba42b42b68098fc +e3ffffb9e5ff1955ad094cbd2366d91053c41154c71659ca2b71e3094fbf1258ca0042b2 +175dcf125ac91359cb155dcc0040b21056c50649b42c6cd60143b10d4fbf2063d60348c1 +0d54d20d56d90952dc0752e10452e60353ea0253ed0252f10052f30052f30253ed0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea0253ea +0253ea0253ea0253ea0253ea0253ea0253ea0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb0253eb +0253eb0253eb0253eb0253eb0253eb0c52d81f4baedbfcff5a77f56586ff6b90ff5b86ff +4e7fe66ca2fc5d8eeb426cd84868ef586ff95265de93a4fee3f6ffc0e3ff2666e41f6aff +2669f82f5cd13c4592e9f8ff104ada1a45c5ffefffcf7a65ec8857f6875adf6a63df7b7d +cd897effded0fff8f4ffebe7a26a59ffefd8fff3dcffedd7b46b5ac7573fef461ffd461a +df4a1f953a28fff8ff143c91043dca0030d50023c00824b3000e8a0023c10039cf0048cb +004dd50054fc0055ff0953f21c5bccd2ffffd7ffff0830761b41ac2d51db2e4ebdeaffff +cfefff073a8d3b71dbcbf8ffd5ffffcafeffc8fcffbbe9ff2655a71c55ac215cb6aee0ff +d2ffffcfffffa9e0ff205abd1754b1205cb4bbf5ffbff6ffbdf3ffcdffffaee8ff78b2ff +0b4abc0a53d40454df0354e40054eb0054f10053f40053f30053f10054ed0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb +0055ea0054eb0055ea0054eb0055ea0054eb0055ea0054eb0055ea0155ec0056eb0155ec +0056eb0155ec0056eb0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec0155ec +0155ec0155ec0155ec0155ec0b53d91e4cacdafcff5372ff5274ff5c85ff618fff4e80f1 +4f80e74873d9557ae45573e35d74e6899dffe3f8ffe7ffff83abf02465e51f6aff2568f7 +2f5cd33c4592e9f7ff114ae21f45ceffedffc86953e37041f4774bfa786bdf6c69c87766 +b08272fff7f6fffcfbfff5e7ffe8d1fff2daa8684db45d41d25330f84213ff4312e64819 +9a3724fff9ff123f900041ce0032d80025c00526b3000f8c0025b2063bc90349dc0052ed +005fff0061ff005aee215dbfebffffefffff022d7b1758ce0a5de72067d3e0fbffeeffff +0b3c981746aeebfefff0fcff00127499bafff1fdffbecef22a5a8ab0e4ffe6fdffa9b9ff +8ba6fddaffffc5f1ff1d4e9d2b5d9accfaffe2ffff7594c387abe5ddffffbee3ff1e4da5 +0d58cd025adf0259e4005aeb005bf6005bf70059ee0258eb005aeb005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb005bed005beb +005bed005beb005bed005beb005bed005beb005bed005beb0059ec0059ea0057eb0058e9 +0057eb0057e80056ea0057e80058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea +0058ec0059ea0058ec0059ea0058ec0059ea0058ec0059ea0056ea0057e80056ea0057e8 +0056ea0057e80056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea0056ea +0056ea0056ea0056ea0755d11e539fd8ffff3c65f54b77ff548bff4d85f65385f45781ed +5572da6a82d8657cb2d3eaffe4feffd6f6ff8fb9ff3f76d3236ae01d6aec246aec295dca +2d4285e0faff1052f11744d5ffedffbd6247de6a3bf9764afa725cf07766c26b4fb17960 +a1847cfff3eefff7e4ffeacfb17050c4744fb15025df6131f44816fb4619d93c1d9c3934 +fff4ff18409f0039d90035eb002ed00020b300159e0023ad0a39c70548df0053f20063ff +0066ff005def245bbff0fefff7ffff00176d2067e30f71fa085ac6eaffffe8f6ff002a8f +2c5dc3ecf3fff6f6ff001970425ab2f7f1fff9faff164161dbffffe0e7ff221c5c383f83 +daeeffd2f0ff1c4388204d84ddffffe9ffff0e244b274375dcf9ffe5feff1942940e59ce +005ce5005be8005cef005dfc005dfc005af1015aec005aef005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1005bf1 +005bf1005bf1005bf1005bf1005bf1005bf1005bf10059f00059f00057ef0058ef0057ef +0057ee0056ee0057ee0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef0058ef0057ef +0058ef0057ef0058ef0057ef0058ef0057ef0058ef0059f1005af10059f1005af10059f1 +005af10059f10059f10059f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10059f10159f10059f10159f10059f10159f10059f10159f10059f10159f1 +0059f10159f10b59d51b569ad5ffff3563f44276ff4e8cff4786ef5085f95780f4627eec +617acebfd9fcd9f8ffbce1ff709ffb336ed62870df1d6ee41b6dea1f6deb245ec9284483 +dcfdff0d52f51745d8fff0ffc86a4ee26b41ed6741fa6f5ce36859e78d75c1836cffe9dd +fff6ecfff3e3fff1daffe3c89b4f2bcf7b4dc75523ed4b1cf74720d93b209c3836fef6ff +17429e0539db0033ee012ed20022b80015a60220b20e38ca0648da0053ea0063ff0065ff +0259f42559cfe2f3ffeaf7ff0128852462dd0d60e4195dccebfeffe4f2ff002290205abe +f1ffffebf0ff0e2b6f405aa5f4f2fffbfdff23496ecaeffffcfaffffedffefe9fff7fbff +edfdff0522642c599cd9ffffe3ffff0c255e3d5ba1e0ffffdefbff0026880c59dd005bf0 +015af4005bfb005dff005cff0059fb0458f60458f90258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb0258fb +0258fb0258fb0258fb0258fb0258fb0457fb0457fb0457fb0456fa0356fa0456fa0255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90255f90355f90255f90355f90255f90355f90255f90355f90255f90355f90255f9 +0355f90355f90355f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90355f90554f90355f90554f90355f90554f90355f90554f90355f90554f90355f9 +0554f90d55dd1d56a5d4ffff3160f43d73ff4788ff4184f54985ff4f80ff5b82fb5074d4 +c7f1ffd8ffff5c92e83a7ae81a67dd247cf81473f51270f4176df41d5fcf234487dcfcff +1153f01c45d1ffeaffcb6b52dc6441ee674ae55c56e97172c36b67ffddd3fff2e1ffead9 +b47266ffeadfffefe1fff1dca26c4aba623ce54b25f74423d93a1c9d382cfbfcff174992 +0e3ccf0a35e40531d20024ba0017a8061dc30f35d60847e00052e80063fa0063ff0759fa +2359dfcae6ffe7ffff709cf32a65cd1b62ce8ec9ffeafeffa8c1ff003cae246acce0f9ff +f5ffff092a6026478af5fcffe3efff001d4fcaf4ffeef1ff3729402b263d171b3e00124a +07286f2b59a7d4ffffdffdff001d633d5db0dcfeffd8f6ff001a86115ae4045df7075cf7 +035dfc005eff005eff055bfc085bf9055bfc045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff045cfe055bff +045cfe055bff045cfe055bff055bfe055bff045afd0659ff045afd0558fe0359fc0558fe +0359fc0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd0258fb0457fd +0258fb0457fd0258fb0457fd0258fb0356fc0157fa0356fc0157fa0356fc0157fa0356fc +0356fa0356fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc0356fa0455fc +0d56e02158abd6ffff305cf03b6dff4483ff3f80f64883ff4e80ff3f6aec6691fab3e4ff +d0ffff4080e42f76f22276fa1e7bff0f72ff0e6eff1369fa195bd521438bddfdff1555ea +2148cbfff0ffab5033d4623ded7253e66d64d36b6affe8e5ffeee3ffe1c8c47a5fc87263 +be6c61ffede4ffe5d4fff5d8b1633fe34b26f6421dd738119a3a22f8ffff154f8e0e42ca +0a38e30834d30027bd0019aa0717de1130ed0844f00051f10060fa0061fd0a58ff1e5ceb +6696ebd4ffffbaf0ff19559d165799d1ffffc6e8ff09336d004fbc1669c9e1ffffecffff +002a54a9d5ffe4feffb5d4ff014189a5e2ffebffffb0b5cbc9d4ead8eeffbbe4ff285bae +2559afd6ffffe0ffff011e6c3759b2d9fcffe2fcff072d98165be40c5df40e5cf00c5df5 +055eff055eff0d5cf50d5df20560f50063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90063f70062f90063f70062f90063f70062f90063f70062f90063f7 +0062f90063f70062f90062f70062f90062f70261f90062f70160f80061f60160f80060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5005ff70060f5 +005ff70060f5005ff70060f50261f90062f70261f90062f70261f90062f70261f90262f7 +0261f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f90262f7 +0360f90262f70360f90262f70360f90262f70360f90262f70360f90262f70360f9105fe0 +285aafdcffff3457e73d65ff467bfb4179f24b7dff4d7bff648cff4871e34b7ccb3770bf +3274e52f79ff247bff106bff146eff1066ff1361ff1852d71f3e90defdff1b56e0244cbe +fff2ffb06339c86836cb6638cb6d51ffebd6fff3dfffead2d6835bd56f47e07257c4614c +bb705dfff0d8ffedc9ffebbfe4491bf34111d43607973a1bf5ffff12548e0649ce0340e8 +0737d50129bf001aab0616e71030f50845f80051f5005ff70260fd0959ff165ffa266dd7 +6eb2ffbcffffc8ffffcbffffafebff588abf00347d116ee5196cd2e3ffffe7feffcaf8ff +d4ffffb9deff00207f0048b10857b4bfe8ffe0fbffdffbffcdf6ff64a4ff0852bd2061c9 +cdffffcbf7ff00227c3363c7d2ffffcef4ff0014831460ea0a62f71060f30d61f50563ff +0563ff0d61f50d62f30366f70068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa0068f80068fa +0068f80068fa0068f80067fa0068f80067fa0067f70066f90067f70065f80066f60066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70066f90067f70066f90067f70066f90067f70066f90067f70066f9 +0067f70066f90067f70065f80066f60065f80066f60065f80066f60065f80066f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80065f60065f8 +0065f60065f80065f60065f80065f60065f80065f60065f80065f60065f80d62e1295cb7 +dbffff2e53df355ef64073f33b73ee4478ff4776ff3c68ef3867ddc0f7ffc8ffff448aff +2777ff1e79ff2685ff0f6aff0d62ff0c5aff114eda1a3c96dbfdff1e59db294eb8fff4ff +9c5127c96736d66d3dd2724cf9a88affefd3c47b5bdc6b41d44f24e5633fe56c4dca6247 +c6694affe9c1ffb183ea4412f23e0dd0320595351df8feff13539a014cdd0044f1063adb +022ac0001bac0319de0d33f00546f60051f5015ff50461fc065bff0c63ff005de31271e5 +055ad10032a2002084002f901055bc1c6be11774ff1e69ded9f5fff0ffff032a770d3ea7 +00128e1856df1470ff0866ee1b59c81c4cb005369d0023990046d50057e81a76f30858c9 +0039a1002590125bce0d54ca0240b10027a10766f60067ff0666f90466fb0068ff0069ff +0367fb0467f90069fd0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff006aff006aff006aff0069ff0069ff0069ff0068ff0068fe006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff006aff +006aff006aff0065fd0065fb0065fd0065fb0065fd0065fb0065fd0065fb0064fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb +0063fd0064fb0063fd0064fb0063fd0064fb0063fd0064fb0063fd0762e7215fc2d1ffff +2153da275bec316eeb2e6ee93873fb3972fd4982ff427df3b0f1ffc1ffff1e6cea176ef9 +1374ff066cff076aff0261ff0159ff054ddd0f3d9fd4ffff1f5ada2e4fb6fff2ffa75233 +c9552ee46137d3532eed7250ce5b3edd5d40ff6746fc5531ec542de9572eec5832e8542e +e55226e64616f53d0bf2390dcd2c0f962e2dfff5ff1a4bb10049f40045ff053ce1022ac0 +001bac001ed10936e70149f30054f40460f10462f6045eff0567ff006eff0071f90e73ff +0a61ef236ced246fee0561e81175ff0767f9276fe7e3ffffecfdff0026852258d2366ffc +115af4005fff1279ff115ee81757db2867f21161f60060ff0075ff0064ee0c6ae8156ae1 +0c5fd71a73f50960e30f5ad71366e8006afe006bff0369fc0169fc006bff006cff006aff +0169fc0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff0069ff +0069ff016aff016aff016aff0069ff0069ff0069ff0068ff0068ff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff016aff +016aff0068ff0068ff0068ff0068ff0068ff0068ff0068ff0068ff0067ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff +0067ff0266ff0067ff0266ff0067ff0266ff0067ff0266ff0b65f11c5fcacbffff1a51d2 +1f59e12c6ae52a68e3346ef4366ef52f66e5437cef2a6bc92e72d52872ed1768ed2782ff +0664ea0c68fb055ef60058f0024cd3083d9dd0ffff1f5dd62e52b3ffeeffa95845bf492f +d24929df5531e15532e7583aea5036ea412af44c2ffa653bdc4818e64415fe5325e93d0d +ef4011ee3c0ee33b17bf2e1d8b2d3dfff1ff1f47b90148f80044ff053ce1022ac0001aab +0020ba0940db0042e4015bf7005ae50666f00057f00372ff0075fd0076ff006eff046aff +1268fd0e6afb0072ff0073ff0670f71864d2ddffffe4ffff001d832764e12a6ef70c61f2 +006cff006dff0e67f71763f41a61fb1064ff006eff0071ff006dfb086af30f68ea0f68ea +0969f40b68f41465ea1066ef016aff006bff0569fd0569fb006cff006dff006bff046afd +0568ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff0667ff +0669ff0669ff0669ff0568ff0568ff0568ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff0467ff +0467ff0467ff0467ff0467ff0467ff0467ff0467ff0566ff0566ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff0765ff0566ff +0765ff0566ff0765ff0566ff0765ff0566ff0765ff0f64f31859cdcdffff295fdd0e43c5 +2359d3295dd72051d23562e32f5bd42f5eca2e5fbe295dc0235acf1d5bd6175cd1155cce +084fc1175ed20d55ce0446b62357abcfffff1b5fcc2653aef7e8ffa566619b342bc64b39 +bf4224c43f1ede4a30d53e29d44233cd452fc44b20c64913d74009dc3b05da3a08d53a0c +d7431fb32c16a735348c4360fef5ff1d41af104aea0544f40b3dde022ac00016a70029c0 +013dd9004bef0059f8055eec0460e7005ceb006cf80077f50078fd0070ff006bff0c68ff +096cff0075ff0078ff0a80ff126de0235ab704329000289e1766e90659e30e6dfb006efb +006ffd046afd0c65ff1360ff0c64ff006eff0070ff006dff066afe0d68f50c68f7056aff +0769ff1166f41066f7026aff006bff0968ff0969fe006bff006dff006cff056aff0669ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff +0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0768ff0667ff +0467ff0467ff0467ff0366ff0366ff0366ff0366ff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff +086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff086bff0265ff +0265ff0265ff0265ff0265ff0265ff0265ff0265ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff0364ff +0364ff0364ff0364ff0364ff0364ff0364ff0c62f31c61d896d0ffa9e0ff2960d40032a2 +0e40b1204cc51038b11b44b01d45a71a469f1845a21342ae0f42af0d44a80c44a1164ba9 +083ea2002f9d1650bcaee5ff8ac9ff2576e92061c7cfdfffd2b8d39d5d787928398b3d3b +98413a952929992c329539468d3e438942308f40219f3817a334169d351c963525822827 +7828358f4e6cecceffb2c5ff2858c7043ad20f44ec0c3ad80028be0016a70021ca0030dc +0048fe004fff0758f00354e3045be90061e70071e50071ee006aff0066ff0864ff0569fd +0073fe0077ff006ef7077dff1068e30051ce0f70fb0069f90c75ff0674ff006ef3006ef7 +006afe0066ff0a5fff0a60ff006af0006dee0069ff0266ff0764ff0664ff0066ff0066ff +0d62fd0b62fd0066ff0066ff0764ff0764ff0067ff0068ff0067ff0067ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0067ff0066ff0066ff +0066ff0065ff0065ff0065ff0064ff0064ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff +0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0061ff0067ff0067ff +0067ff0067ff0067ff0067ff0067ff0067ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff0066ff +0066ff0066ff0066ff0066ff0066ff0766f81562d80b4fb4a1e1ffb8f7ffcdffffcfffff +d2ffffd1fcffd6ffffd6ffffd6ffffd5ffffd5ffffd2ffffd2ffffd4ffffd3f8ffd9ffff +cefdffbbf2ff99d7ff115ed40061eb005adf104aabaec9fff5f6fffaf2fff7fafffbfaff +ffe7fffff0fffcf6fff6f9fffafafffff9fffff5fffff4fffdf6fff8f7fffaf5fffbf5ff +eaedffabc6ff1254b40045bb1c55ec1443e70c38d50028be0015a60023d80033ea0149ff +044fff094ee90b4edd1055e1095add0065d50066de0060fe025cff0d5cff0b60f90167f7 +006df9006afc0062f60d70ff1372ff0672ff0059f11179ff0054e1006aeb006bef006afb +0065ff0c5cff105cfd0965e40567e20064f80063ff0461fa0361fe0063ff0062ff085ffa +0a5ff80062ff0063ff0860f80860f60064ff0064ff0064ff0064fe0063fe0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff +0162ff0162ff0162ff0162ff0162ff0162ff0162ff0162ff0063ff0164ff0064ff0063ff +0063ff0063ff0062fe0062fe0062fe0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff +0165ff0265ff0165ff0265ff0165ff0265ff0165ff0265ff0165ff0062fe0062fe0062fe +0062fe0062fe0062fe0062fe0062fe0062fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe0061fe +0061fe0061fe0061fe0061fe0560f51b6cef0651c6165fc61c60c3215ec91850c12154ca +2d5fd0285abd285bb7285ab9285abd2659c4265ac0265cb2295cad365dba2b50ba2353cf +2863e50447c90d60ea0062fc0058f0125fdf1e55cc2b49cb2543bb1749a82554ac374ab0 +2638a42550b91f54b42554a62b53993051962c52991e57a61b56b21a49b31a43b51a45b8 +0942b50660d2004dcd0840dd0a35da0d38d50028be0016a7001ad90030ed003bf20141eb +043ccf1041ca123dca1446cb0447b80049c20244e30441f10c42ed0d44e90848e6004ce8 +005bfb0058f70051ee0047e2005bf40055ee0054eb0c5dec0050d00052d20054e20051eb +0447f00d44e50d49cb064ec70050da0052e10050dc0051e10053ed0052ec004edc004eda +0051e60051e6004fd6004fd50052e10054e40053e10052dd004edd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd +004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ddd004ede004fde004ede004fde +004ddd004edd004cdc004ddc004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df004fdf0050df +004fdf0050df004fdf0050df004fdf0050df004fdf0050df0048d80049d80048d80049d8 +0048d80049d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d80048d8 +0048d80048d80048d80047de003cde0d5ef8014fd7044dce003fcd0945db0c44df063dd5 +0a44cc0945ca0944d00743d50844da0845d40848c40b49b80b41ab0a3faf1753d50039c5 +0853e2004ce20041e40462ff0b53e6002dbf1838d9274be70036b90036b52746d52540d7 +093dce0242c80244be0645b60844b60346b9004bc7004ad00039c50e4bd9002ab4002cb3 +003cbf0051df0035df1139e80d37d70028be0017a80024df0839ed033ddf0034c3194ac0 +1c42ad1932a61c34a01e43941b45991841b51840c31d40c01e40bc2141b81c43ba0538b7 +0c43c2154bc50542b5024cb9064db90033a6254fbb1946a1114aa30050b3004dbf1342c6 +1f3ebd2341a31d459c0f4bad094db20d4bae094db2014fbe024ebc104aae124aab084cb7 +094cb51449a5144aa4094db0054eb5064eb20b4cb01249ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae1448ae +1448ae1448ae1448ae1448ae1448ae1448ae1348ae1247ad1148ad1148ad1047ac1047ac +1047ac0f46ab0f46ab0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a80c43a8 +0c43a80c43a80c43a80c43a80c43a80c43a80c43a80e45aa0e45aa0e45aa0e45aa0e45aa +0e45aa0e45aa0e45aa0f44aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa1044aa +1044aa1044aa0c44b31753d70026a4003ca10e46a71141af1640b9123bbb123bb71543b2 +1444b01243ba1143c01142c31143bc1246ab14489c1948961847991547aa0339a61951c0 +0340b30248c2003ab21040af1334a71d30b31e3ab80747ab0042a30d30a61029a81837b4 +113bb10841a80743a30d41a60b42a90244b40045b70d4abd0a3eae153ba63863cb0644ab +0035a90d3ac90d34cf0d36d00027bd0016a70017c20533cf255cdb2d63c5b4e1ffc5e4ff +e5f0ffebf1ffddeafad9edf4d3ecffd0ecffd2ecffd6ebffdeeaffe2e7fffaf7ffe1deff +e2e6ffd7e7ffd2efffdffaffeaeeffe3ddffe8e5f6dbebf8c4f4ffc1f3ffd3e8ffe0e3ff +e8e2ffe7e5fbe1e8ffdee9ffe1e8ffdee9ffd4ebffd5ebffe3e6ffe5e6ffdce9ffdee8ff +eae5fbeae5f9dee9ffdaeaffdbeaffdceaffdee9ffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaffdeeaff +deeaffdeeaffdeeaffdeeaffdeeaffdceaffdbe9ffdaeaffd9e9ffd9e9ffd8e8ffd8e8ff +d8e8ffd8e8ffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedffddedff +ddedffddedffddedffddedffddedffddedffdbebffdbebffdbebffdbebffdbebffdbebff +dbebffdbebffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaffdceaff +dceaffdaebffdbf2ffc9e1ffeeffffe7faf8d5e1efe7ecffe7ebffe0e6ffdeebfcdbecfe +d8ebffd7eaffd4e9ffd4ebffd6eefad9eef1dbe9f2e5f2ffdfecffdfedffc9d7fcdaeaff +ecffffd2e3ffe1e8fbf7f3ffefe4ffdae0ffcdffffcbffffd6f6ffebf3fff3e1fff0e3ff +daefffd5f1ffe1eaffe5e8ffe3e8ffdeeaffd3e4ffd8e4fcece9fcddd9f0dae7ffddf4ff +d4f4ff2146b00b35bf0024ba0014a50021c70433c92b63da1d51a4d8faffd0e2f6ecf0ff +e1dfeceeefdfecf2d8e6f2e6e4f1e8e5f1e3e7f0dfeceddbf3e9ddf5ddddfde3e4ffeee7 +ece6d6f1f6dfe4e6d1fdeee7f8e1dbfee9d8f3eed8dff6e4dbf6efe9edf8f3e9f4fae8e6 +fbe9dff7e8e1f6e9e1f9e8e0f6e9e3efeaeef0eaecfae7e0fbe7def6e8e7f7e8e5ffe6d9 +ffe6d7f7e8e1f3eae5f4e9e3f4eae1f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0 +f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f2ece0f2ece0f2ece0 +f2ece0f2ece0f2ece0f2ece0f2ece0f2ece0f2ece0f2ece0f2ece0f2ece0f2ece0f2ece0 +f2ece0f2ece0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0 +f2ece0f3ebe0f2ece0f3ebe0f2ece0f2ecdef2ecdef2ece0f3ebe0f3eae1f3eae1f3eae1 +f3eae1f3ebe0f3ebdef3ebdef3ebdef3ebdef3ebdef3ebdef3ebe0f3eae1f3eae1f3eae1 +f3ebe0f3ebe0f2ece0f2ece0f2ece0f2ebe1f2ebe3f2ebe3f2ebe3f2ebe5f2ebe3f3eae3 +f2ebe1f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0 +f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0 +f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0 +f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0 +f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0f2ece0f3ebe0 +f2ece0f3ebe0f2ece0f3ebe0f2ece0f1ede1f1ede1f1ede1f0ece0f0ece0efebdfefebdf +efebdfeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeebdceeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadef0eadeeeeadef0eadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdf +f1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdf +f1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebddf1ebddf2eadf +f1ebdff2e9e0f1eae0f1eae0f1eae2f1eae2f1eae2f1eae2f1eae0f1eae0f1ebdff1ebdf +f1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdf +f1ebdff1ebdff1ebddf1ebdff1ebddf1ebdff1ebddf1ebdff1ebddf1ebddf1ebddf1ebdd +f1ebddf1ebddf1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdfefebe0efebdfefebe0 +efebdfefebe0efebdfefebe0efebdfefebe0efebdfefebe0efebdfefebe0efebdfefebe0 +efebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdf +f1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdf +f1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdf +f1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdf +eeebe2e7e8e3f4f6e9e5e7c2f1efc6eae3c7f8eddbf0e4d8f5ebdff2edd7efefd7eceee3 +ebede8eaece9eaede4e9efd3eaefcfedebd4f2efe0f6f1edddd7d7fffcf9f2ede7dfdbd0 +fdf7e7efe3cbfae9d5feeae1ede9ddd1f0cecef8d2def4dfedeae3ffe1e6ffe2e4ecece0 +e8efdff4e6e3f8e4e3f6e4e2f3e6e0f0eedff8f3dff6e1ccfee7d7f6ede6e0e6f6cae2ff +2a4ca30b32b50021b70012a1001cc50838d61e60ea1f55b5d9ecffededede7e9e6ebeee5 +eeeddbeeeddbebece4ecebe6efebe0f1ebddeeecddefebdff3e9e0f3e9e0f2eadfefecdd +eeecddeeecddf2eadff3e9dff3eadbefecdbeaeee0e8eee4ecebe6efeae6f2e9e0f2eadf +f2eadff1ebdff2eadff1eae0efeae4efebe2f2eadff3e9dff1eae0f2e9e0f5e9ddf5e9db +f2eadff1eae0f1eae0f1ebdff1ebdfefebdff1ebdfefebdff1ebdfefebdff1ebdfefebdf +f1ebdfefebdff1ebdfefebdff1ebdfefebdff1ebdfefebdfefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efebdfefebdff1ebdfefebdff1ebdfefebdff1ebdfefebdff1ebdfefebdff1ebdfefebdf +f1ebdfefebdff1ebdfefecddf1eedbf3f0ddf1eedfe8e1d7efe8e2f6eceaeee5e0f5eae4 +f6ece2f9f0e1f0e7d6e8e0cdf1e9d6f6eedbf3ead9f1e9dcf3eae5f2eae7f2ebe3f2ebe1 +f2ecdef0eddef0ece0f0ece1f0ebe5f0ebe8f0eaecf0eaecf0eaeef0eaecf2e9eaf0ebe7 +f2ebe1f0eddef2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0edde +f2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0edde +f2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0edde +f2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0edde +f2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0eddef2ecdef0edde +f2ecdef0eddef2ecdef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0eddef0edde +f0eddef0eddef0eddef0eddeefeddeefeedcefeddeefeddef0eddef0eddef2ecdef2ecde +f1ebdff1ebdff0eadef0eadef2eadff2ece0f4ece1f4eee2eeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadef0ece0eeeadee5e1d5ede9ddf2eee2ede9ddefebdfeae6da +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf2ebd9f2ebd9f3e9ddf2eadf +f3e8e2f2e9e4f2e8e6f2e8e7f2e8e7f2e8e7f1e9e7f1e9e6f1eae4f1eae0f1ebdff1ebdd +efebdfefebdfefebdfefebdfefebdfefebdfefecddefecddefecddefecddefecddefecdd +efecddefecdbefecddefecdbefecddefecdbefecddefecdbefecdbefecdbefecdbefecdb +efecdbefecddefecddefebdfefebdfefebe0efebe0efebe0eeebe2eeece0eeebe2eeece0 +eeebe2eeece0eeebe2eeece0eeebe2eeece0eeebe2eeece0eeebe2eeece0eeebe2eeece0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0 +eeebe2eeecdfefedd8efedd6f1ecd9f1ebddf1ebdff1ebdfefecdbefecdbeeece0eeebe2 +eeebe2eeece0eeeddbeeedd9efecdbefebdfefebe0efebe2efebe2efebe0efebdfefecdd +f2ebdbf2ebdbf3e9dfefebdfe8f0dbe5f1dbeaeedfeeece0f2e9e0f2e9e0f1ebddf2eadf +f6e6e7f5e7e6f1ebdfeeeddbebecdcf1eedff9e9dcf9e9dcedeadbe8f2fbd1e7ff2748a9 +1035b90021b300129e001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddecebd7efeedaf2efe0eeeadff4ede7f4ece9ece2e0efe4e0ede3d9 +f0e7d8f8efdefff7e4fbf3e0f0e9d6f1e8d7f8f0e3f1eae4f1e9e6f1eae2f1ebdfefecdb +efecd9eeeddbeeecdfeeebe2eeebe6eeeae9eeeae9efe9e9efeae7efeae6efebe2efebdf +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddeeecddeeeddbeeeddbeeeddbefecddefecddf1ebddf1ebddf3ede1 +f2ece0f3ebe0f3ebe0f3ebe0f4ece1f5ede2f5efe3f3ede1f1ede1f1ede1f1ede1f1ede1 +f1ede1f1ede1f1ede1eeeadeefebdffefaeeece8dcf0ece0e8e4d8eae6daf7f3e7efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff1ebddf2ebd9f3ead9f3e9ddf3e9dff3e9e0 +f2e9e2f2e9e2f2e9e2f2e9e2f2e9e2f1eae4f1eae4f1eae2f1eae0f1ebdbf1ebdbefecdd +efebdfefebdfefebdfefebdfefebdfefecddefecddefecddefecddefecddefecddefecdd +efecdbefecddefecdbefecddefecdbefecdbefecdbefecdbefecd9efecdbefecdbefecdb +efecdbefecddefebdfefebdfefebe0efebe2efebe0eeece0eeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9 +f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1035b9 +0021b100129c001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddeeebdaefecdbefebdff2eee3f6efe9f2ebe5f0e9e3f2e9e2f5ece3ede5d8 +efe8d8f2ebd9ede6d6ede7d7f0e8dbeae4d8f2ebe1f2ece0f0eddcf0eddaf0eed9f0eed7 +efefd7efeed9efeedcefeddeefeddeefeddeefeedaefeed9efefd5efefd7efeedcefede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efeddeefeddeefeddeefeddeefeddef0eddef0eddef0ece0f0ece0eee8dceee8dc +ede7dbede7dbefe7dcefe7dcf0e7def0e9dfefe9ddede9ddede9ddede9ddede9ddede9dd +ede9ddede9ddeae6dae3dfd3f4f0e4e4e0d4fbf7ebfbf7ebebe7dbede9ddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff1ebddf2ebd9f2ebdbf2eadff2e9e0f2eadff1ebdb +f1edd4f1edd0f1edd0f1edd4f1ecd9f1ebddefecddefecdbefedd6efedd6efecdbefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdd +efebdfefecddefebdfefecddefecddefecddefecddefecdbefecddefecddefecddefecdd +efebdfefebdfefebdfefebdfefebe0efebdff1ebdbf1ecd9f1ecd9f1ecd9f1ecd9f1ecd9 +f1ecd9f1ecd9f1ecd9f1ecd9f1ecd9f1ecd9f1ecd9f1ecd9f1ecd9f1ebdbefecddefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7 +eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1035b90021b1 +00129c001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff5f2e3f0eddeeae6daf1ede2f2ebe3f0e9e1faf3ebf6efe7f4ede3f6f0e4f9f3e7 +efe9dde7e1d5f4f0e5fcf5edebe4daf2ece0f2ecdcf0eddaf0eed9f0eed9f0eed7efeed9 +efeed9efeed9efeed9efeed9efefd5eff0d1eff0ceeff1cceff0d0efeedaefede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0efede0 +efede0efede0efeddeefede0efeddef0ece0f0ece0f0ece0f0ece0f5efe3f4eee2f4eee2 +f3ede1f4ece1f5ede2f6ede4f5eee4f5efe3f3efe3f3efe3f3efe3f3efe3f3efe3f3efe3 +f3efe3ede9ddf6f2e6f5f1e5f3efe3ece8dcede9ddeae6daf5f1e5efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddf1ebdbf1ebdff2e8e6f1e9e7f1e9e6f1ebdff1edd2 +f1eecdf1eecdf1edd0f1ecd9f1ebdfefebdfefecdbefedd4efedd4efecdbefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0 +efebdfefebe0efebdfefebdfefebdfefebdfefebdfefebdfefecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdff1ebddf2ebd9f2ebd8f3ebd8f2ebd8f3ebd8f2ebd8f3ebd8 +f2ebd8f3ebd8f2ebd8f3ebd8f2ebd8f3ebd8f2ebd8f3ebd8f2ebd9f1ebddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddb +eaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1035b90021b100129c +001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f7f1e5f4eee2eae3d9f4ede3ede9deeae6dbf6f2e7e0dcd1dfdbd0ebe7dcf6f2e9f2eee5 +e7e2dce7e4dfeee9e5ede8e2ece8dcece9d8ece9d8ece9d8ece9d8ece9d8ece9daece9d8 +ebead8ebead6e9ebd3e9eccfe9edcce9edc8e9eec5e9edcaebead6ebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9ddebe9dd +ebe9ddebe9dcebe9ddebe9dcebe9ddebe9ddece8ddece8ddede9deede9deeee7ddede6dc +ede6dceee7ddefe6ddefe8deefe8deede9deede9deede9deede9deede9deede9deede9de +f5f1e6f5f1e6d5d1c6faf6ebe6e2d7f1ede2f1ede2eae6dbefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddefeae4f1e7efefe7f4efe7f2efe9ebefecddefedd4 +efedd4efecd9efeae4efe9e9efe9e9efebe2efedd6efeed2efecdbefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebe0efebe0efebe0efebe0efebe0efebe0efebe2efebe0 +efebe2efebe0efebe0efebe0efebe0efebe0efebe0efebdfefebe0efebdfefebdfefebdf +efebdfefebdfefebdff1ebddf3eadbf3eadbf5e9dbf3eadbf5e9dbf3eadbf5e9dbf3eadb +f5e9dbf3eadbf5e9dbf3eadbf5e9dbf3eadbf5e9dbf3eadbf1ebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8 +ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1035b90021b100129c001cc7 +0738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0e9df +f4ede5ebe4daf8f1e7eeeadee7e3d7ede9ddbbb9acbbb9adb2afa6a4a19aa9a6a1b5b1ae +aba7a4a4a09fb1aea9b1ada1b1ae9fb1ada1b1ada2b1ada4b1aca6b3aca6b1aca6b1ada4 +b0aea1b0af9daeb09aaeb196adb292adb391adb294aeaf9fb0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4b0aea2b0ada4 +b0aea2b0ada4b0aea2b0aea2b0aea2b1ada2b1ada2afaba0afaba0b0a99fafa89eafa89e +afa89eb0a79eb0a99faeaa9faeaa9faeaa9faeaa9faeaa9faeaa9faeaa9faeaa9fa8a499 +a5a196bab6abfffff4eeeadff6f2e7f4f0e5e7e3d8efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddefedd8eeecdfefe8efefe7f6efe6f7efe8f0efebe2efecd9efecd9 +efebdfefe9ebefe8f0efe9edefeae4efeed2efeecfefecd9efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebe0efebe0efebe0efebe0efebe2efebe2efebe2efebe2efebe2 +efebe2efebe2efebe2efebe2efebe2efebe2efebe0efebe0efebe0efebe0efebdfefebdf +efecddefecddf1ebddf2e9e0f3e9e0f3e8e2f3e9e0f3e8e2f3e9e0f3e8e2f3e9e0f3e8e2 +f3e9e0f3e8e2f3e9e0f3e8e2f3e9e0f3e8e2f2e9e0f1ebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecde +f1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1035b90021b100129c001cc70738db +1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1eae0ede4ddf7eee9 +ebe4dcf7f1e5edeadbebe8d9edebdca4a5975e5e5477776f6b6a6662615d7a7977797876 +6b676475726b706c60726c5e726b63726a6772696c72687073687072687072696e706a6c +6f6b686d6d656d6d636c6e616c6e606c6e616d6d636d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d636d6d656d6d63 +6d6d656d6d636f6c636f6c636f6c636f6c63747067747067736f64726e63736c62736c62 +736c62746d63726e63726e63726e63726e63726e63726e63726e63726e6379756a6d695e +e6e2d7fffff4e7e3d8ddd9ceebe7dcfffef3efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefedd8eef0cbecf0cfeeebe2eee9efeee8f4eee9efeeebe2eeeddbeeeddbeeece0 +efe9edefe8f0efe9ebefebdfefefcbefefc9efedd8efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe2efebe2 +efebe2efebe2efeae4efeae4efeae4efebe2efebe2efebe0efebe0efebdfefebdfefecdd +efecddefebdff1e9e6f1e8e9f1e8ebf1e8e9f1e8ebf1e8e9f1e8ebf1e8e9f1e8ebf1e8e9 +f1e8ebf1e8e9f1e8ebf1e8e9f1e8ebf1e9e7efebe2efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2 +f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1035b90021b100129c001cc70738db1c60f3 +1c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1eae0efe6e1faefebeae1d8 +f3ede1ebe8d7f0efddf5f6e6a6a79974756dedeee8fffffdf7f6f4fdfcf8fffffaf9f6ef +fffff3ffffecffffeafffef1fffdf6fffbfffffafffffafffffafffffafffffbfffffdff +fffefffffefffffffffefffffefffffffffbfffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffafffff8fffffa +fffff8fffff8fffff6fffff8fffff6f7f3eaf7f3eaf6f2e9f5f1e6f6efe5f6efe5f6efe5 +f7f0e6f4f0e5f4f0e5f4f0e5f4f0e5f4f0e5f4f0e5f4f0e5f4f0e5e9e5da7d796ef6f2e7 +fcf8edf4f0e5f6f2e7eae6dbede9deefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeedd8eef0cbecf0cdecece0eceaedeee9f0eee9edeeece0eeedd9eeeddbeeece0efe8ef +efe7f2efe8f0efeae4f1edd2efeecfefecd9efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebe0efebdfefebdfefebdfefebdfefebdfefebe0efebe0efebe0 +efebe2efebe2efeae4efeae4efeae4efebe2efebe2efebe0efebdfefebdfefecddefecdb +efebdfeeeae7eceaebeeeaebeceaebeeeaebeceaebeeeaebeceaebeeeaebeceaebeeeaeb +eceaebeeeaebeceaebeeeaebeeeae7efebe2efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0 +f4eadeecebd9e8f3f9cfe7ff2747ae1035b90021b100129c001dc80738db1c60f31b54bb +e0e9fff4ebe2e9ecdbecf1ddeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeae6daf8f4e8ede9ddf3efe3f6f2e6e8e4d8f9f5e9e6e2d6 +eceadef7f5e9e7e5d9e9e7dbf7f5e9f4f2e6f7f5e9e9e7dbe5e3d7f4f2e6f3f1e5e0ded2 +f9f7ebe9e7dbf1efe3efede1ece8dceeeadef1ede1eae6daf0ece0efebdfebe7dbf0ece0 +e5e1d5f8f4e8e3dfd3f6f2e6efebdfe5e1d5efebdfede6dcf4eae8f0e5e1f6ede4eee8da +efecd9efeedaeeefdfa8aa9d666761fffffdfffffde2e1dffffff8fffcf1fffeeeffffe7 +fdf9d4ffffdbffffe3f9f1defffcf4fffbfafffafdfdeef3fffbfff5ebecfff9fafffdff +fcfafffcfbfffefdfff3f3fdfbfbfbfcfbf6fffffbfffffaf4f3effffffafdfcf8fffffa +fffffbfbfaf5faf9f5fefdf8fffffbfbfaf5fffffbfffffafffffbf4f3eefffffbf5f4ef +fffffbfdfcf7fbfaf6fffffafdfcf8fefdf8f5f4f0fffffaf3f2eefefdf8fffffbfaf9f4 +fffffbf8f7f2f9f8f4f8f7f2fffffbfffffafcfbf7fefdf8fffffbf9f8f3fffffbfdfcf7 +fffffbf1f0ebfffefafffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffafffff8fffffafffff8fffcf5efece3fffff6fffff6f9f5eafffff4fffff4fffcf1 +fffff6fcf8effefaf1fffdf4fffff6f6f2e9fffff6fffff6ada9a0726e65f5f1e8fffdf4 +f0ece3f0ece3ede9e0efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeeadef2eee2f4f0e4f0ece0ebe7dbebe7dbefebdff3efe3efebdff7f3e7e9e5d9ece8dc +f0ece0ede9ddf0ece0f2eee2eeeadeebe7dbf4f0e4e4e0d4ebe7dbf7f3e7e7e3d7f2f0e1 +fefde8d8d9c9f1f0eeeae7eee4dfe6f9f5f4f1efe0eeedd8e8e5d2f0ece1ede3ebf1e6f7 +f6eafef1e6f4e0d6d5f5eee6eeeadff2eee3e8e4d8ede9ddfaf6eaeae6daeae6daf3efe3 +e4e0d4fffdeee6e2d6efecddf3f0e1e9e6d7e9e6d7f1eedfe7e3d7faf6eaece8dcf7f3e8 +040000fbf7eee2ddd7f5f0eaefeae4ede9e0f2eee3f6f2e6f9f5e9edeadbe2dfcef2f0e1 +e9ebe0dce2d8f9fcf3e0e6dce1e4dbf5fbf1ebeee5e6ece2dee1d8f3f9efe8ebe2dbe1d7 +f7faf1edf3e9eaede4e6e8ddeceadef2eee2ede9ddf8f4e8eeeadefaf6eaf0ece0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdf +eaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eade +ecebd9e8f3f9cfe7ff2747ae1338bc001dad00119b001dc80738db1c60f31b54bbe0e9ff +f4ebe2e9ecdbecf1ddeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdffcf8ece7e3d7ebe7dbefebdfe0dcd0d6d2c6f3efe3f8f4e8edebdf +f3f1e5e7e5d9fffff4e0ded2e1dfd3dbd9cdf4f2e6f8f6eaefede1dcdacefbf9edebe9dd +eceadedfddd1faf8ecf0ece0f1ede1e7e3d7fdf9edece8dcede9ddf7f3e7e8e4d8eeeade +faf6eaf4f0e4f1ede1e3dfd3f7f3e7ebe7dbf2ebe1f4ebe6f0e5e1f6eee3eee8d8efecd9 +efeedaeeefdfa8aa9f747570fffeffe6e4e5fffffafffff3fcf5e2ffffe3b4af85b2b077 +afab6eb9b381ffffdcfceed4fffcecfff1e4fffceffffceffffdf1fffef3fffbf5f7f3f4 +fffefff6f5fffefdfff8f8fafffffbf2f1edf1f0ecfffffbecebe7fffffbfffffbf6f5f1 +fffffbfffffbfffffbf1f0ecfffffbf1f0ecf9f8f4faf9f5f2f1edfdfcf8fffffbfffffb +fffffbfdfcf8efeeeafffffbfffefafffffbf7f6f2fffffbfbfaf6f8f7f3fffffbfefdf9 +fffffbfffffbfffffbfbfaf6f8f7f3fffffbfffffbfffffbfffffbfffffbfffffbfaf9f5 +fcfbf7fffffbf2f1edfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffdfffffbfffffb +fffffafffffafffffafffffaf4f1eafffef8d6d2c9ece8dff1ede2ebe7dceeeadfe0dcd3 +fbf7eef2eee5efebe2ede9e0f1ede4e7e3dae8e4dbada9a0726e65f5f1e8fffdf4f0ece3 +f0ece3ede9e0efebe0efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdff3efe3 +ebe7dbeae6daf1ede1f5f1e5f1ede1ede9ddece8dce5e1d5e9e5d9f9f5e9f4f0e4f2eee2 +eae6daede9ddeeeadef6f2e6f0ece0faf6eaefebdfece8dcf3efe3e7e3d7eeece0dfdcd3 +edece7f8f7f5f6f5f3030000030200090a000404000c0c00f1edd2f5eee4eee3e7fbeffb +ecdeedfff7fff5eaeefaf3edf2eee3f8f4e9e5e1d5e5e1d5fcf8ecf4f0e4e8e5d6fcf9ea +dbd8c7fbf8e7e7e4d1edead7fffce9efecd9fcf9e6f8f5e2e4e1d0e3e0d1f6f2e6f6f2e7 +e8e4dbf7f3eaece7e1f5f0eae2ddd7f3efe6f1ede2d9d5c9f1eeddffffefe4e5d70a0f0b +000204000204060e1000020400020400050700020401090b0005070002040a1214000204 +0006080002040d1110f2f2e8f0ece0e9e5d9e2ded2f1ede1e5e1d5ebe7dbfffbefefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedf +ebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9 +e8f3f9cfe7ff2747ae1338bc001dad00119b001dc80738db1c60f31b54bbe0e9fff4ebe2 +e9ecdbecf1ddeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfe5e1d5f1ede1f9f5e9ece8dcfffff3fffff3e0dcd0f1ede1eeece0e8e6da +f4f2e6e8e6daeeece0faf8ecfdfbeff3f1e5e8e6daebe9ddf9f7ebedebdfe6e4d8f6f4e8 +f8f6eadfddd1f5f1e5f0ece0f8f4e8d5d1c5e7e3d7fdf9ede3dfd3f6f2e6f5f1e5f1ede1 +d4d0c4f7f3e7f3efe3ece8dcf2eee2ece5dbf4ebe6f0e5dff6eee1eee9d6efedd8efeeda +eeefe1a9a9a16c6a6bfffdfffffdfdf2ebe3fffbe8ffffdfa79f70fdf7b9ffffb6ffffaa +f1eba1aea467fffbcafff9d0ffffd8fff1caffffd8fff9d2fff9d5ffffe6fdfaebfffffb +f1f1f9fefefff7f7f9fffffdfffffdfffffdf1f1effffffdfffffdefefedfffffdfbfbf9 +efefedf7f7f5fffffdfbfbf9fffffdfffffdfcfcfafffffdf5f5f3fffffdf9f9f7fbfbf9 +fdfdfbfffffdfffffdfffffdededebfffffdf9f9f7fefefcfffffdfffffdfffffdfffffd +fefefcededebfffffdfffffdededebfffffdfffffdf5f5f3f7f7f5f2f2f0fffffdfffffd +e7e7e5fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffffffffdfffffdfffffb +fffffbfffffafffcf7ebe8e1f4f1eafffff6f6f2e9e4e0d7fffef3e4e0d5fffcf3e6e2d9 +f3efe6eeeae1f4f0e7e4e0d7f9f5ecfcf8efada9a0726e65f5f1e8fffdf4f0ece3f0ece3 +ede9e0efebe0efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdff5f1e5eae6da +e7e3d7efebdff4f0e4f0ece0eeeadef0ece0fdf9eddcd8ccf8f4e8e5e1d5f1ede1f3efe3 +f2eee2e7e3d7efebdfe5e1d5f3efe3f1ede1ebe7dbf0ece0ede9ddf0ede4f3eff0f3f1f2 +dedbd2030200eaeac6fafccbebefb4f1f3b2eaecab070600fbf8cbf3edcde4dbcafdefec +f7e8efecdfe6ebe3e0dbd7ccf7f3e8f7f3e8e8e4d8f4f0e4e6e3d4eeebdae6e3d0f4f2dd +ecead5eeecd5f7f5dedad8bff5f3dae5e3caf5f3dceeecd7ece9d6f1eedd040000f5f1e6 +f0ece3e9e5dceae5dfe9e4deebe7def9f5eafcf8ecedead9e7e4d3eeede8000015676d91 +4f557960668a5c628643496d676d915a6084585e82494f736a70945a60844d537753597d +676d91000015e9e8e6eeeadefefaeef9f5e9e8e4d8eeeadef3efe3dbd7cbefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeedd +f3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9 +cfe7ff2747ae1338bc001dad00119b001dc80738db1c60f31b54bbe0e9fff4ebe2e9ecdb +ecf1ddeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff1ede1ebe7dbe8e4d8070300f0ece0dad6cae9e5d9f9f5e9fcfaeee3e1d5f9f7eb +eeece0efede1e0ded2e5e3d7ebe9ddf5f3e7e2e0d4eceadee4e2d6f5f3e70d0b00f1efe3 +eceadef0ece0d2cec2fffff3efebdff3efe3eae6da130f03ece8dce3dfd3f0ece0f2eee2 +faf6eaf5f1e5e1ddd1ece8dcfff8eef4ebe4f0e6ddf6efdfeee9d5efedd8efeedceeeee2 +a9a8a3737174fcf7fbfff9fafffdf3f0e5c9ac9f72ffffc3ffffaef4f192ffffa1ffffaf +ffffbaaea061aa9a5fa3925ab4a56aa6985baea467ffffcdffffd6ffffe6f0eee2ffffff +eeedf5fffffffffffdebebebfffffdfdfdfdf9f9f7fbfbfbfffffdf7f7f7fffffdffffff +fffffdf4f4f4fefefcfffffffffffd000000f7f7f5fffffff5f5f3fffffffffffdfafafa +f6f6f4fafafaececeafffffffffffdfffffffffffdfafafafffffdfdfdfdf0f0eef6f6f6 +fffffdf6f6f6eeeeecfffffff1f1effffffffefefcfffffff5f5f3fffffff5f5f3ffffff +f3f3f1fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffdfffffd +fffffbfffffaf6f3eefffff8e7e4ddf5f1e8e8e4dbe4e0d5faf6ebe4e0d7f0ece3eae6dd +f5f1e8e5e1d8fffdf4e8e4dbe7e3daada9a0726e65f5f1e8fffdf4f0ece3f0ece3ede9e0 +efebe2efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdff0ece0f1ede1f0ece0 +ebe7dbeae6daede9ddf3efe3f6f2e6eae6dabfbbaff6f2e6e0dcd0f1ede1f7f3e7f7f3e7 +e8e4d8efebdfe3dfd3ece8dcf1ede1ebe7dbf0ece0f3efe3f0ece1f5f2edebe9dc080900 +0d11000b1000060b00060b000d1100070c00181b001013000a09001712000b03001b1000 +0a0000f9f2e8fffef5e9e5dce6e2d7f1ede1fbf8e9e9e6d5ebe8d5f7f5e0f0eed7f3f1d8 +e8e7cbf4f3d5efeecff8f7d8e5e4c5eeedcf040300fffee5e5e3cef5f2e1ebe7dbe4e0d5 +120e05f4f0e7fffef8e4e0d7d9d5caf9f5e9faf7e8ece9d8e9e8e410152b000023000023 +00052a000023040c310000230000230003290a1237000023000023050a3000002300052b +000017ebe9eaf4f0e4eae6daf2eee2dcd8ccfbf7ebf9f5e9f5f1e5efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9dd +f6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff +2747ae1338bc001dad00119b001dc80738db1c60f31b54bbe0e9fff4ebe2e9ecdbecf1dd +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +e9e5d9fefaeef1ede1040000fbf7ebfffff3ede9ddf0ece0e6e4d8f8f5ece7e4dbdbd8cf +faf7eef9f6ede3e0d7f8f5ecf0ede4e8e5dcfefbf2edeae1eae7de030000ece9e0edebdf +fcf8ecf6f2e6e4e0d4ebe7dbf7f3e7eae6daf0ece0eae6daf7f3e7e4e0d4fffff3e4e0d4 +e1ddd1fcf8ecebe7dbece6daf4ebe2f0e6daf6efddeee9d5efedd8efeedceeeee4a9a8a6 +746f76fff9fffffbfbfef1e1ffffd8b0a265fbec9bfff596fdf894ffffa6fffaa3e5d88a +ffffbcffffbdffffbdffffbaffffb2b3a75b726b25ffffc9fffbd5ffffedefeeecfffeff +ffffffeeeeeefffffffffffff4f4f6f5f5f5fffffff3f3f3ffffffd7d7d7fefeffffffff +f4f4f6fffffffffffffcfcfc000002fffffff6f6f8fffffffbfbfdfffffff8f8faffffff +fffffff8f8f8fdfdffffffffededeff6f6f6fffffff5f5f5fffffffffffff6f6f8ffffff +fffffff7f7f7fcfcfefefefef6f6f8fffffffffffffffffffbfbfdffffffe7e7e9ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffefffffefffffffffffffffffffffffffffdfffffdfffffb +f5f4eff7f6f1fffff8e4e1daf6f3eadddad1fffff4e1dfd3efebe2f1ece6efeae4e6e1db +f9f4eeece7e1d7d2ccfffdf7ada8a2726d67f5f0eafffcf6f0ebe5f0ebe5ede8e2efebe2 +efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfece8dcf5f1e5f3efe3eae6da +ece8dcf6f2e6f1ede1e0dcd0a4a094a09c90fffbeff2eee2f2eee2e9e5d9efebdfeeeade +f7f3e7f4f0e4f1ede1f2eee2f0ece0f0ece0f2eee2eae7d6e9e8ccf3f4c8040a00f1fa9f +e4ed84eff88beff68feff48ee2e87cf0f57fe0e662fcff79eaed6ae8e974f3f093ffffc6 +070100dbd7cef9f5ecf2eee3eeeadee8e5d6eeebd8f4f2dde7e5cce4e3c7f6f5d7040400 +050500151500040400f1f1cbe5e5c1ffffe1040300f0efd3070500fdfae9040000eae6db +e3dfd6e2ded5e7e3dafdf9eeece8dcd9d6c7f1eeddf1f1e5000104f7fffff8ffffe1ecf2 +f8fffff3fefff5fefff7fffff0f9ffedf8fef8fffff6fffff3fcfff7fffff8ffff000508 +eeeee6f6f2e6e3dfd3ede9ddfcf8eceeeaded9d5c9f3efe3efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8df +f6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae +1338bc001dad00119b001dc80738db1c60f31b54bbe0e9fff4ebe2e9ecdbecf1ddeeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff6f2e6 +e0dcd0fffdf1040000f7f3e7e4e0d4fcf8ece8e4d8e8e5dce3e0d7f1eee5fdfaf1efece3 +e3e0d7faf7eee3e0d7f8f5ecdfdcd3e9e6dde6e3dafcf9f0030000f5f2e9eeece0e1ddd2 +e7e3d7faf6eae8e4d8faf6eaede9dde6e2d6fffef2f2eee2f1ede1dedacef8f4e8e7e3d7 +e9e5d9f7f3e7faf4e8f4ecdfefe8d8f6efdcecead3efedd8efeedceeeee6aba7a86c646f +fffafffff5f4fffceaffffd1aa9850f8e888d4c55eb0a645938930a89b4dc2b16bb7a462 +ad9857b6a25daf9c50ae9d4bb7ab57a89f528f8a4afffcd2fbf9e4fffefdfefbfffffeff +fcfcfefffffff6f6f8fefefffffffffffffff7f7f9fdfdfffffffffffffffafafcffffff +f3f3f5fffffffdfdff09090bfffffffafafcfffffffffffffafafcf5f5f7fcfcfef8f8fa +fffffffffffffcfcfefffffffffffffbfbfdffffffefeff1ffffffffffffececeef8f8fa +fffffff6f6f8fffffffffffffffffffcfcfefcfcfefffffffffffffffffff9f9fbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffefffffefffffffefffffffffffffffffffffffffdfffffdfffffb +f5f4efeeebe4f3f0e9f2efe6fffff6e4e2d6f3f1e5f4efe9dbd6d0fbf6f0fef9f3ded9d3 +f6f1ebf2ede7efeae4ada8a2726d67f5f0eafffcf6f0ebe5f0ebe5ede8e2efebe2efebe0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfece8dcf1ede1eeeadeece8dcf6f2e6 +faf6eadedaceb9b5a9b4b0a4b8b4a8fcf8ecf6f2e6f4f0e4eae6daefebdff0ece0dedace +f8f4e8f0ece0ebe7dbf1ede1efebdff1ede1ece9d6f6f5d7d8daa8192000e2e989eff790 +e9ef8ff3f4a60e0c00f9f8a6f7f892feff7af1f65bf2f856f9fe64f7f775e5e1860d0900 +fffcf6eae5dfe2ded5f7f3e7efecddf1eedbf0eed7ffffe5f3f2d4040400e5e5bfecedc5 +e0e1b7e6e7bb0d0e00eaebc3d6d6b0ffffdc080700e5e3ca080500e1decff7f3e7f7f3e8 +fffff6e7e3daefebe0faf6eaece9daf3f0dfe8e8dc000200f4fcfe979fa1151d1ff9ffff +000204020a0cf5fdfff9ffff949c9e131b1df5fdff000204000204f9ffff040807f5f5eb +e9e5d9faf6eaeae6daede9ddece8dcfffcf0e6e2d6efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9 +f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1338bc +001dad00119b001dc80738db1c60f31b54bbe0e9fff4ebe2e9ecdbecf1ddeeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0ece0e9e5d9 +eeeade191509e2ded2efebdfede9ddeeeadeebe8dffffef5030000030000030000f5f2e9 +faf7eeece9e0030000211e15030000eeebe2fffff6030000edeae1efede1040000f8f4e8 +e4e0d4f0ece0ede9ddf0ece00b0700e2ded2040000fdf9ed070300040000fffff3e6e2d6 +040000eae4d6f4edddefe8d6f6f0daecead3efedd8efeddef0ede8aba6aa6e646ffffaff +fff1f1fffce6fff7c4a2903efff488bcab3fd5c671ffffbdffffc3fff1baffebb8fffec8 +ffffc1fffdb7fffeaffff09ffcf0a47b7335ffffdafffeeefffcfffcf8fff6f5fbf7f7f9 +030305000002101012ffffff0000020d0d0ff4f4f6f8f8fafcfcfe000002020204000002 +ffffffffffff000002ffffffffffff000002ffffffffffffffffff0c0c0e0d0d0f000002 +f8f8fafdfdff000002050507000002000002ffffffffffffededef161618000002ffffff +f7f7f9010103040406000002000002fffffffcfcfeeaeaecfffffffbfbfdffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffefffffefffffefffffefffffffffffffffffffffdfffffdf9f8f4f6f5f0 +fffff8e6e3dcf3f0e7ebe8df030100050300040000110c06040000050000060100e4dfd9 +f5f0eae6e1dbada8a2726d67f5f0eafffcf6f0ebe5f0ebe5ede8e2efebe2efebe0efebdf +efebdfefebdfefebdfefebdfefebdfefebdff0ece0ece8dcede9ddf2eee2f1ede1dfdbcf +c0bcb0a7a397aca89ca6a296aca89ca9a599b1ada1b0aca0b0aca0aca89cb5b1a5f5f1e5 +f0ece0e5e1d5f1ede1ece8dceeeadef2eee2dbd5c7ffffe4060700f3f6b3eeeeb0fdf8ce +0800000c00000d0000e3d8abf2ef8ef5f770f1f55af6fa5dffff74f7f591070300ebe6e0 +e9e4def3efe6faf6eae7e4d3e3e1ccf6f4dbe3e2c40404001f1f00090a00040500040600 +202200040600040500181900090900040400ecebcff6f4df060300efebdf0a0600cecac1 +fffbf2e3dfd4ede9ddf1eedff7f4e3eae7e0000009fcfdff13142816172be7e8fcfcfdff +fcfdfff3f4fff4f5ff111226090a1efcfdfffcfdfff9fafffcfdff00000be1ded9efebdf +eeeadef9f5e9ebe7dbf4f0e4ede9ddf3efe3efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7 +eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1338bc001dad +00119b001dc80837db1c60f31d54bbe0e9fff4ebe2e9ecdbecf1ddeeeddbefebdfefeae4 +f1eae4f5e8dff5e9dbefebdfeceddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfe9e5d9f5f1e5f0ece0 +040000fcf8ecede9ddefebdff3efe3edeae1030000f2efe6ebe8dffbf8ef030000e2dfd6 +080500faf7eed9d6cdfdfaf1040100e1ded50d0a01f5f2e9030100f6f2e7e0dcd0f2eee2 +f3efe3f0ece0e3dfd30d0900ebe7db040000070300e4e0d4f6f2e6040000f4f0e4ede9dd +f3f0e1f4edddefe8d6f5f0daecead3eeedd8efeddef0ede8aba6aa7c717ffff7fffffbf8 +ffeed4ffffc6bba750efdb68ae9d2bfff3a4ffebaefff5bcfff7bffff5bbffedaefff4ad +fff6a6fffca6d3c36effffb8797133ffffdcfffdedfffdfffefbfffffeffffffff000002 +fffffff6f6f8000000fffffff8f8f8050507fbfbfbfffffffffffff4f4f6ffffff000002 +ffffff111113f0f0f0000002ffffffffffffffffff000002fafafafafafcffffff000002 +f9f9f9060608f9f9f9ffffffffffff000002ffffff000002f9f9f9fcfcfe000000ffffff +000000fefefff6f6f6ffffff000000f9f9fbfffffffffffffbfbfbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffefffffefffffefffffefffffffffffffffffffffdfffffbfffffbedece7fefbf4 +eae7def3f0e7dedcd0fffff40301000400000400000d0802040000f1ece6fcf8efddd8d2 +f5f1e8ada8a2726e65f5f0eafffdf4f0ebe5f0ece3ede8e2efebe2efebe0efebdfefebdf +efebdfefebdfefebdfefebdfefebdff3efe3ece8dcf1ede1f6f2e6e0dcd0bab6aaa8a498 +aeaa9eada99db7b3a7aaa69aada99dafab9faaa69aada99dafab9fa5a195fefaeefcf8ec +e9e5d9f4f0e4e8e4d8e8e4d8f1ede1fcf6eadcd8bf0f0f00eaeaaeedebb20f0800110500 +0c00000f0000130600faf49cf2f077f8f866f6f75dfaf969efec83080400ebe6e2f9f5e9 +ebe8d5e5e3cef9f7e2eeebdaede8d5f4f0d7181600dadaa4e8eba8ffffbaeaeda0e0e299 +f2f4abf2f3a5e5e59beeeeaeedebba0a0700040200e5e2d3faf7eee6e3dcfffcf5e6e3da +f1ede2f4f0e4e3e0d1f8f2e2eae7e201000dfefbffece8fffefafffefbfffdfbfff9f7ff +fefcfffefbfff7f4fffefbfffefcfff8f6fffefcfffdfaff010011f5f1eeede9dd0d0900 +0400000400000e0a00040000f2eee2efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddb +eaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1338bc001dad00119b +001cc80837db1c60f31d54bbe0e9fff4ebe2e9ecdbecf1ddeeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeeecdfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeae6dafcf8eceeeade090500 +eae6daeeeadef9f5e9eae6daedeae1030000f1eee5ece9e0f6f3ea030000f3f0e7030000 +e8e5dceeebe2e8e5dc0e0b02e2dfd60d0a010f0c03e3e1d5e6e4d8eceaddfffef1e7e5d8 +f0eee1f1efe2070500f2f0e3030100f3f1e4eceaddedebde0e0c00f3f1e4dcdacdf6f2e6 +f4ecdfefe8d8f5f0dcecead5eeedd9edeee0eeede9aba6aa726a77fff4fcfff8f3fffce0 +ffffc5a9983edccb55baa633fff5a8ffeeafffe9a6ffe89effed9affef95ffef8effed89 +fff08ddecd71c5b76c80773cfffed8ffffedfffffdfffefffefefefbfbf9040404fcfcfa +fcfcfc040402fbfbfbfefefc070707fffffdfcfcfc000000060606050503000000fffffd +010101090907fffffff6f6f4f7f7f7fffffd0000000000000b0b0b0000000b0b0bfdfdfb +000000fffffdfefefefffffd000000fffffdf2f2f20a0a08fdfdfdfafaf8ffffff000000 +fffffffffffdfbfbfb000000fcfcfcf8f8f6fffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffffffffff +fefffffefffffefffffefffffffffffffffdfffffdfffffbfdfcf7f3f3ebfffef7eae7de +edebdfe8e6d9eceaddf3f1e5050100040000040000e7e3d8faf6ede8e4d9e4e0d7faf6eb +ada9a0726e63f5f1e8fffdf2f0ece3f0ece1ede9e0efebe0efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff3efe3ece8dcf1ede1f6f2e6e0dcd0bab6aaa8a498aeaa9e +aca89cb4b0a4a8a498ada99db2aea2ada99daba79baaa69aa19d91fcf8ecefebdfe6e2d6 +f7f3e7e9e5d9f0ece0f1eedff2edd9f6f2cf080700f4f5a9e7ea8ff3f594eceb8f0d0900 +e8e48bfbf698ebe77cffff93eeeb68f9f669f0ed5efaf68a070200e7e4ddf3f3d7edeec6 +eaeac4f3efd2ece5dbf4ebe4f7eedd080400fefdaaf3f786f3f877ebf06ff9fc87f1f27a +f9fa70ebec64fbf98cffffae080400f7f3da0d0a01e4e3e1ebebebebece7ecece0eeecdd +efecdbf1ecd9f2ebdbefeae406040ffcfcff8987af0e0c34fcfcff000010030511fafcff +fbfaffa5a4c611112bf6f8ff000005000106fcfdff00000eefebe8e6e2d6fffdf1040000 +0400000c0800f3efe3efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8 +ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1439bd001eae00119b001cc8 +0837db1d5ff31d54bbe2e8fff4ebe2eaebdbecf1ddeeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff9f5e9e4e0d4ede9dd040000fcf8ec +e4e0d4f0ece0f7f3e7edeae1070400eeebe2e6e3daeeebe2040100ebe8df030000f1eee5 +f3f0e7eae7de090600fbf8ef030000dfdcd30b0900fffff4d6d4c7efede0eae8dbe7e5d8 +fbf9ec030100e8e6d90b0900fcfaede7e5d8eeecdf030100e1dfd2fffff3dedacef3ede1 +eee8daf5f0ddebead6eeedd9edeee0eeede8a9a7aa6b656ffffbfffffcf6fff5dbffffc6 +af9f48c3b441c3af3efff7a2fff0a6ffec99ffec90fff08afff386fff281fff082fbe57f +cfbe6480722bffffcdffffe3f7f3e7fffdfff6f5fbfffffffffffd000000fffffdfffffd +000000fffffdfffffd000000fffffd080806fffffdfffffdfcfcfa000000f8f8f6000000 +efefed000000fffffdfffffdfffffd000000fffffdf9f9f7fcfcfafafaf8fffffd050503 +e7e7e5fffffdfffffd010100fbfbf9fcfcfafffffd030301fffffdfefefc000000fffffd +fbfbf9fffffd070705fffffdfefefcfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffffeffff +fefffffefffffefffffffffdfffffdfffffbfffffafffffaf6f6eefffff6efece3f5f3e7 +edebdeebe9dcedebdef0ece1040000fcf8edf5f1e6e1ddd2fbf7ecfffcf1e3dfd4ada99e +726e63f5f1e6fffdf2f0ece1f0ece1ede9deefebe0efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff0ece0ece8dcede9ddf2eee2f1ede1dfdbcfc0bcb0a7a397a6a296 +a7a397b5b1a5afab9faeaa9ea7a397aba79bada99dc6c2b6fffff3f2eee2eae6daf7f3e7 +ebe7dbf2eee2ebe8d7f1ecd8f1edca080500e2e395fafc97ecf17be6ea6f101200ffff91 +eae877f4f084e9e375fffa85fff97df7f36df6f18d140e00f7f3f4ededd1eff0c6efedc6 +f5f1d4eee4e2f3e9eaf7ebdf0a0300f3f391dbe159f8ff63f2f85affff77ecee5fffff5c +e4e446fdf97befec8f080500f7f3dae3e0db070709ebebedeaece7ecece0eceddbefecd9 +f1ecd9f2eaddf1eae4000007fcfcff222048181540e9e9fffcfefffbfefffcfffffcfcff +06052706061efcfefffcfffbf2f7f3eef0ff0b0a18f0ece9f9f5e9cfcbbffaf6ea1a160a +d5d1c5f9f5e9e1ddd1efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecde +f1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1439bd001eae00119b001cc80837db +1d5ff31d54bbe2e8fff4ebe2eaebdbecf1ddeeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfe8e4d8e7e3d7fdf9ed0a0600ede9ddf3efe3 +f0ece0eeeadefcf9f0030000ebe8dfebe8dffdfaf1080500e5e2d9050200eae7def1eee5 +ece9e0050200e2dfd6120f06eae7def2f0e4030100fdfbeeeeecdff0eee1edebdee5e3d6 +0b0900f4f2e5030100e6e4d7e7e5d8fcfaed040200f6f4e7ebe9dcf7f3e7f3ece2eee8dc +f5efdfebead6eeedd9edeedeedeee6a9a7a869646bfffbfffffbf7fffce5ffffcda29245 +ab9e38fffd8effec86ffe782fee37afde374ffe671ffe871ffe773fce476fbe484d4c270 +847438fff4cdfffdedfffcfdfff7fffcf8fff4f3f9ffffff000000ffffffffffff000000 +fffffff4f4f4070707f3f3f3000000fffffffafafaffffff000000ffffff0d0d0df2f2f2 +ffffff000000fffffff8f8f8080808f7f7f7ffffffffffff000000eeeeee040404ffffff +fffffff7f7f7090909ffffff060606f5f5f5ffffff000000ffffff000000fefefef6f6f6 +ffffff000000f6f6f6fffffffffffff6f6f6ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffeffff +fffffffffffffffffdfffffdfffffbfffffafefdf8f0f0e8fcf9f0e9e6ddf2f0e4edebdf +eceaddedebdef6f2e7e8e4d9e5e1d6f0ece1f5f1e6e7e3d8e3dfd4f0ece1ada99e726e63 +f5f1e6fffdf2f0ece1f0ece1ede9deefebe0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfece8dcf1ede1eeeadeece8dcf6f2e6faf6eadedaceb9b5a9b0aca0b5b1a5 +fdf9edfefaeefffff3fffef2fffff3fffff3ebe7dbfffff3eeeadeeeeadef4f0e4ede9dd +f6f2e6e8e5d6ece6d8eae6cb121000f0f1adedf097ffff9ef9fd8f0c0e000d0b002c2800 +0e09000f09000f0a00fffb91f6f17cfcf5a4070000f0e9f9ebe7dbfaf9ddeeeacfefead7 +ede2e6f6ebf1efe2d9181100eaea88ffff86eff65af1f85ae4e758fdfe72e5e64dffff7f +e8e572f9f4a20e0a00f0ebd5f7f4efebebedebebebeaede6eceddfeceddbefecd9f1ebdb +f2eadfefeae606050bf9fafff8f6ffedebfffcfcfffcfefffcffffebeef5fcfcfffcfbff +fcfdffd8dbe2fcfffbfcfffbedeffc00000be6e3defffbeff3efe3ece8dce9e5d9fdf9ed +f2eee2f0ece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2 +f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1439bd001eae00119b001cc80837db1d5ff3 +1d54bbe2e8fff4ebe2eaebdbecf1ddeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfebe7dbfffdf1e4e0d40400000b0700040000040000 +0e0a00dfddd1f5f2e9070400100d04030000e8e5dce8e5dcefece3030000151209030000 +e3e0d7fdfaf1030000ece9e0f0eee2efede0030100eceaddf3f1e4fffff2e4e2d5030100 +e7e5d8110f02f6f4e7f0eee1e8e6d90e0c00e5e3d6030100efebe0f3ece4eee7ddf5efe1 +ebead6eeedd9edeedeedefe4a8a8a66c6a6ffffbfffff8f6fffeecfffdd3b6ab69a59943 +fff690f8e474f6e16af5df67f4de64f8e064f9e167f8df6bf3dc72edd87bb3a05484733d +ffffdcf7ebdffff5f9fffafffffcfffffdffffffff010101f8f8f8f8f8f8010101ffffff +ffffff050505fffffff8f8f8000000111111000000070707f4f4f4000000ffffffefefef +ffffff080808fefefef4f4f4030303010101000000ffffffffffff000000000000030303 +010101ecececfffffffbfbfb040404040404ffffffefefef101010000000040404030303 +fbfbfbfdfdfdfffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffeffffffffff +fffffdfffffdfffffbfffffbfffffafffff8f5f5edfffdf4eae7def1efe3eeece0efede0 +f4f2e5f3efe4ebe7dcf7f3e8f6f2e7dfdbd0fffdf2efebe0f9f5eaada99e726e63f5f1e6 +fffdf2f0ece1f0ece1ede9deefebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfece8dcf5f1e5f3efe3eae6daece8dcf6f2e6f1ede1e0dcd0aba79ba39f93fffbef +f4f0e4f9f5e9f0ece0f2eee2ebe7dbf7f3e7f7f3e7e8e4d8eeeadeefebdfece8dcf8f4e8 +eae6daf9f5ecfffaea060300ebeab2edefa4e1e48de7eb8df2f396ffffb2e7e495fff9af +f0eaa0fdf6a6f2ec96e3dd7ff0e8a9110809fff9ffdfdad6ebe8d5eae5d1fcf6eaf8edf5 +ece1e9faf0e70a0200f4f399e6ea6fffff7cf0f662f7fa75f0f171fffd78e2de61f4f08d +fcf8af080300e4dfcbe7e4dff8f6f7ebebe9ebece4eceddfeceddbefecdbefecdbf2e9e0 +efeae605040aeff0ffafaece121131fcfdff000009060a0bfcfffff9faffdcdcf4040615 +fcffff000200000300fcffff02020cedeae5ece8dcebe7dbeeeadef3efe3ede9ddede9dd +f4f0e4efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0 +f4eadeecebd9e8f3f9cfe7ff2747ae1439bd001eae00119b001cc80837db1d5ff31d54bb +e2e8fff4ebe2eaebdbecf1ddeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff1ede1f0ece0ede9dde5e1d5f9f5e9faf6eaf0ece0e2ded2 +e7e5d9fefcf0e4e2d6eeece0e3e1d5f5f3e7f9f7ebf0eee2f6f4e8e4e2d6f7f5e9fcfaee +e1dfd3edebdfeeece0edebdffefcefe3e1d4f4f2e5f7f5e8e0ded1f1efe2f8f6e9f3f1e4 +dcdacdf6f4e7dedccff5f3e6eceaddf3f1e4f4f2e5ebe7dcf3ece6eee7dff5efe3ebead8 +eeedd9edeedcedefe2a8a9a3707072fffefffffefbfff8ebfffddcf8f1bdbab16e998e35 +ae9e2db09e20af9b1eaf9b1eb19b21b09b24b09a2bae9833a7933c907e36ffffcafff4cf +fffeecfffcf7f1ebeffffdfff9f7fafffffffdfdfdfffffffffffffdfdfdfffffff8f8f8 +fffffff8f8f8fffffffffffff0f0f0fffffffffffffffffffdfdfdffffffffffffffffff +fbfbfbf0f0f0fffffffcfcfcfffffffffffffafafaffffff000000fffffffafafaffffff +fffffff5f5f5fffffffffffff1f1f1ffffffffffff000000fffffffefefef1f1f1ffffff +fffffffcfcfcfefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffdfffffd +fffffdfffffbfffffbfffffafefbf4f4f1eafffff6ece9e0f1ede2eae6dbe9e5d9ede9dd +e2ded3f6f2e7ece8dde8e4d9f5f1e6e6e2d7f1ede2e6e2d7ada99e726e63f5f1e6fffdf2 +f0ece1f0ece1ede9deefebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f0ece0f1ede1f0ece0ebe7dbeae6daede9ddf3efe3f6f2e6e5e1d5c7c3b7fffff3e9e5d9 +e9e5d9e7e3d7eeeadeebe7dbf3efe3ebe7dbe8e4d8f1ede1ece8dceae6daf6f2e6ede9de +eae5e2ddd9d0131100f3f1c8f4f5bbeaeba7eaeca3fbfbb3eae9a9f7f2b8ece5b1f4edb9 +e8dfa8fdf5b7fcf3b0fff7c9060002ebe4f6eee9e3f9f6e3e9e4d1f3ece2f8edf5eee2ec +f2e7e50c0600f3f1a7eff289d7db62ffff88f6f88af6f58bfefa8ef5f08cfbf6a5e0dba1 +151100e9e6d5faf7f2e7e6e4ebece6ebede2ecedddeceddbefecdbefecddf2e9e2efeae7 +000004fefdff0b092104021af8f7fffeffffeaecebfefffffefdff06051721212df9fafc +f5f8f1fbfef7f8f9fe050409f3f0e9dcd8ccf6f2e6fbf7ebe6e2d6e0dcd0f9f5e9e9e5d9 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdf +eaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eade +ecebd9e8f3f9cfe7ff2747ae1439bd001eae00119b001cc80837db1d5ff31d54bbe2e8ff +f4ebe2eaebdbecf1ddeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1ede1f0ece0f2eee2f8f4e8ebe7dbdbd7cbfffff3faf6eaf1efe3 +edebdfe1dfd3f2f0e4f7f5e9f3f1e5e4e2d6e7e5d9eae8dcebe9ddeeece0f1efe3ebe9dd +f8f6eae6e4d8f2f0e4dfddd0fcfaedeae8dbdddbcef4f2e50c0a00030100f2f0e3f2f0e3 +f8f6e9f4f2e5e6e4d7fdfbeee2e0d3edebdefaf6ebf3ece6efe6e1f5eee4ece9d8eeedd9 +ecefdaedefe1a7aaa1717171f7f7f7fffefdfffdf2ffffeaffffdde9e3b3a59c5b8d7e29 +8f7f1f917e20917e20917c21907c25907b2a8e7a318f7b3cffffccfffcd8fffbe1fffdf1 +fffdfafffbfffcfafffffffffefefefffffffdfdfdfdfdfdfffffffefefefffffff5f5f5 +fffffffffffff3f3f3fffffff9f9f9f8f8f8f8f8f8fefefefffffffafafaf5f5f5ffffff +f6f6f6fffffff1f1f1f3f3f3fffffffbfbfbf4f4f4242424ebebebfffffff5f5f5f9f9f9 +fdfdfdf5f5f5fffffffdfdfde5e5e5ffffff000000f9f9f9ffffffffffffffffffffffff +e7e7e7ffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffdfffffdfffffdfffffbfffffb +fffffafffffafffff8faf7f0f1eee7fffff6f3f0e7fdf9eef6f2e7f4f0e4f5f1e5f5f1e6 +efebe0eae6dbfffff4e2ded3f7f3e8f0ece1e8e4d9ada99e726e63f5f1e6fffdf2f0ece1 +f0ece1ede9deefebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff5f1e5 +eae6dae7e3d7efebdff4f0e4f0ece0eeeadef0ece0f7f3e7dfdbcffffef2ede9ddf3efe3 +f4f0e4faf6eaf7f3e7f0ece0ebe7dbf0ece0f3efe3ede9ddece8dcf1ede1efebe2f1edec +f5f1ee0503000403000c0d000d0d000607000706000c0a00080300080200080200150d00 +0a02000b03000a01001d1415dbd6dcf5f2e3fdfbe4ebe6d0eae4d8f5eaf0f2e6f2f4e8ea +130b00efeab3edec9cffffade6e589f0ed9ee8e598e5de8dfbf4a6eee8aaf8f1c50d0700 +f6f3e4ece9e2e7e6e1ecece2ebeddfeceddbeceddbefecddefebdff1eae2efeae70c0a0d +fefefff1eefffefdfffffdffe8e9ebfffffdfefffff5f3fef7f7fffbfafffbfdfcfffff8 +f8fbf2ffffff000000e4e1d8fffef2ece8dceae6dafaf6eaf7f3e7ddd9cdf7f3e7efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedf +ebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9 +e8f3f9cfe7ff2747ae1439bd001eae00119b001cc80837db1d5ff31d54bbe2e8fff4ebe2 +eaebdbecf1ddeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfe9e5d9f1ede1f2eee2e6e2d6f2eee2ebe7dbfaf6ead8d4c8e3e1d5faf8ec +fbf9eddddbcffaf8ecedebdfe3e1d5fbf9edfdfbeff3f1e5ebe9ddebe9ddf1efe3fdfbef +dfddd1f6f4e8f7f5e8f2f0e3e2e0d3fcfaedf1efe2f5f3e6e1dfd2eeecdfeceadde5e3d6 +f8f6e9e7e5d8f5f3e6dad8cbf5f3e6e5e1d6f3ebe8efe6e1f5eee4ece9daeeedd9ecefda +edf0dfa7aa9f6f716cf3f3f3fcfcfafffffafffff3ffffe8ffffe3fbf5d3fffddefffddf +fffce1fffce1fffce1fffbe3fffbe4fffbe6fffaebfdede0fffcf6fffcfbf8f2f6fffcff +fffdfffdfdfff7f7f9fffefffffefffdfbfcfdfbfcfffefffffefff8f6f7fffefffcfafb +fffdfef5f3f4fffefffffefff3f1f2fffefffffefffffefffffefffffefffffefffbf9fa +fffefffffefffffefffdfbfcfffefff5f3f4fdfbfcfffefffdfbfcfffefffdfbfcfffeff +faf8f9fffefffffefffcfafbfffefff9f7f8fdfbfcfffefffffefff1eff0fffefffffeff +e4e2e3fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffffdfffffbfffffbfffffbfffffbfffffa +fffffafffff8fffff8f4f1e8f7f3eae2ded5efebe0efebe0ede9deece8ddf2eee3e4e0d5 +efebe0ede9def2eee3e8e4d9faf6ebede9deada99e726e63f5f1e6fffdf2f0ece1f0ece1 +ede9deefebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff3efe3ebe7db +eae6daf1ede1f5f1e5f1ede1ede9ddece8dceeeadeeae6daf3efe3eeeadef1ede1e9e5d9 +e6e2d6dfdbcfeeeadeefebdff4f0e4f0ece0eeeadef0ece0ede9ddefebe2e8e4e5f7f5f6 +e8e8def5f4dff7f8d8dddeb6f7f8d0f5f3cdfaf7d8e9e3c9f4eed8ebe4d1fef6e3f2ead5 +f4edd1f4eed6ded8ccfffff1e2e1c3dfdfbbf3f0d1faf5e1faf1f2ece2ebe6dbe3150c05 +0802000804000a05000a04000a02001b12001b14000c05000c0500080200070000e7e3d8 +f5f2ebedede5ecece0ecedddeceddbeceddbefecddefebe0f1eae4efeae7010000000004 +0300090a09110100040e0e0c0a09050001000a080b030305050304030400010100000100 +0f0e0a010000f1eee5ebe7dbf4f0e4e0dcd0f7f3e7e9e5d9f6f2e6ece8dcefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeedd +f3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9 +cfe7ff2747ae1439bd001eae00119b001cc80837db1d5ff31d54bbe2e8fff4ebe2eaebdb +ecf1ddeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff2eee2ebe7dbebe7dbf9f5e9f4f0e4e4e0d4fbf7ebfcfaeededcd0eae8dc +fffff3d6d4c8f5f3e7efede1e9e7dbe4e2d6efede1f0eee2eceadeeeece0dbd9cdfffff4 +e1dfd3ebe9dcefede0eeecdfe7e5d8f7f5e8e6e4d7f3f1e4eceaddf6f4e7e8e6d9edebde +efede0e4e2d5fdfbeee7e5d8f6f2e7f3ebe8eee6e3f5eee4ece9daeeedd9edefdaedf0df +a7ab9d6c6f68fefffdfffffff4f4f2fffffafcfaeeffffeffffbeffff9f9fff9fffff9ff +fff9fffff9fffff9fffff9fffffafffffbfffffbfffffafdfffefff8f8fafefffff7fbfc +f8fcfdfffffffffefffbf9fafffefffffefffbf9fafffefffffefffefcfdfaf8f9fffeff +fffefffcfafbf4f2f3fffefff4f2f3fffefff7f5f6fcfafbfffefff8f6f7fffefffffeff +f6f4f5fcfafbfffefffffefffffefffaf8f9fbf9fafffefffffdfefcfafbfffefffffeff +f6f4f5fdfbfcfffefff8f6f7fffefffffefffffefff4f2f3fffefffffefff1eff0fffeff +f3f1f2fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffffdfffffbfffffafffffbfffffafffffafffff8fffff8 +fffff8fffff6dedbd2c8c4bba39f96ada99eafaba0aeaa9faba79cafaba0b1ada2b1ada2 +aaa69bafaba0aca89da8a499aeaa9fada99e726e63f5f1e6fffdf2f0ece1f0ece1ede9de +efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeadef2eee2f4f0e4 +f0ece0ebe7dbebe7dbefebdff3efe3ede9ddf5f1e5e8e4d8ece8dcf2eee2f0ece0f5f1e5 +f8f4e8ebe7dbf0ece0f3efe3eae6daefebdff4f0e4ebe7dbefece3ede9eae6e4e5ecece4 +f3f4e4e9e9d1edeecff5f4d6e9e8ccf0eed9e9e6d5fcf6eaf6efe5e2dbd1fffaeee2dacd +fcf7e4f1eedbf3f1d8efefc9f4f5cdfdfad7e7e2ccede5e2f9eff7f6ebf3f4eaebf0e7d8 +f4edd3fbf4d7efe8cefdf1e5ece0d2efe6c7f1e9c4ede6c9f5efd9fdf7e9f4f0e7e6e3da +f3f0e7eceddfeceddbeceed9eeeddbefecddefebe0f1eae4efeae6ede9e8f0eeefe4e2e3 +f6f4f5e8e7e5ebeae6f1f0ebefeee9e9e8e4ebeae6f1f0ebe5e4dfefefe7edede5efefe7 +f2efe8ece8ddeeeadeede9ddf3efe3ebe7dbf0ece0ede9ddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9dd +f6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff +2747ae1439bd001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dc +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfefebe0f5eee8e9e2dcf1eae0f3f0e1ebead8f5f6e4e1e4d3a5a799 +73766dedefeafefffdf7f7f7fcfcfafffffbf7f6f1fffefbfffcfffffbfffffbfffffbff +fffbfffffbfffffcfffffdfffffefbfffff8fffff6fcfff3fbfff1f9ffedf8ffedf9fff1 +fffffafffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffafffff8fffffafffff8fffff8fffff8fffff8fffff6 +fcf8ef837f765a564d7a766d766f6570695f7c756b736c62747065747065747065747065 +7470657470657470657470656b675c868277dcd8cdfffff4eeeadfece8ddfdf9eee8e4d9 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeebe2eeeae7ecebe7ecece2eceddf +eceed9eceed6eeeed6eeedd8eeeddbeeecdfefebe0efebe2efeae4efeae4f1eae2efebdf +efedd8efeed2efefcbefefc9f1eecdf1ecd6f1eae4f1e8ebf1e7eff1e8ebf2e9e2f2eadd +f2eaddf2e9e0f3e7e9f3e7e7f3eadbf3ebd6f2ebd9f2eaddf1eae0efebe2eeebe2eeece0 +ecedddeceddbeeedd9eeeddbefecddefebe0efebe2efeae6eeebe6eeebe6eeebe6eeebe4 +eeebe6eeebe6eeebe6eeebe4eeebe2eeebe2eeebe2eeebe2eeebe4eeebe4eeebe2eeece0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8df +f6e6e9f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae +1439bd001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeece0f0ece3e9e2daf2eee3f4f0e4e9e7d8f3f1e2ebecdcc1c3b5dddfd4 +f6f9f0ebece7e1e1dffafafaf9f9f9e9e7e8f4f2f5f1f0f6f1effaf1f0f8f1f0f8f2eff8 +f2eff6f1f0f6f1f1f3f0f2efeef3ecedf5e8ebf6e5eaf8e1eaf8dfe9f9dcebf7dff1f2ea +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1eff2f1edf2f1ef +f2f1edf2f1eff2f1edf2f2eaf2f2eaf2f2eaf2f2eaf4f1eaf4f1eaf4f1e8f4f1e8fffff6 +ece8dff8f4ebfffef5ece5dbece5dbfdf6ecf2ebe1f4f0e5f4f0e5f4f0e5f4f0e5f4f0e5 +f4f0e5f4f0e5f4f0e5ece8dde8e4d9fffff4fffff4e5e1d6e5e1d6f8f4e9eeeadfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebe0eeebe4ecece4ecece2eceddfeceddd +eceddbeeeddbeeeddbeeecddeeecdfeeebe2eeebe2efeae4efeae4efeae4efebe2efecdd +efedd8efeed2efeed0f1edd4f1ecd9f1eae4f1e8e9f1e8ebf1e9e7f2e9e2f2e9e0f2e9e0 +f2e9e4f2e7ebf2e8e9f2e9e2f1ebdff2e9e0f1eae2efebe2efebe0eeece0eeecdfeceddd +eceddbeeeddbeeeddbefecddefebe0efebe2efeae4eeebe6eeebe4eeecdfeeecdfeeebe2 +eeebe4eeebe6eeebe4eeecdfeeecddeeecdfeeece0eeebe6eeebe4eeecdfeeecddefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9 +f3e7e7eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1439bd +001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfefebe0e8e4d9f3efe3f6f2e6e8e6d9eeecdff5f3e6e4e5d7fffff4fffff6 +fafaf2fffefafffffdfffefff9f7f8fffffffefffffefffffefffffefffffefefffefeff +fcfffffcfffffbfffffbfffff9fffff9fffff8fffdf8fffbf8fffbf9fffafffffafffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffa +fffefbfffffafffff8fffff6fffff6fffff6fffff6fffff6fffff6fffff6f6f2e9fffbf2 +fffef6fffef6fef7effffef6fffdf6fffbf3fffff4fffff4fffff4fffff4fffff4fffff4 +fffff4fffff4fffff4fffff4fffff4fffcf1eeeadfece8ddf2eee3ede9deefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeece0eeece0eeece0eeecdfeeecdfeeecdd +eeecddeeecddeeecddeeecdfeeecdfeeece0eeebe2eeebe2eeebe2efeae4efeae7f1e9e7 +f1eae2f1eae0f1eae0f1eae0f1eae4f1e9e6f1eae4f1eae2f1ebddf1ebdbf1ebdbf1ebdd +f1eae0f1eae2f1eae2efebe2f1eae4efebe2efebe2eeece0eeece0eeecdfeeecddeeecdd +eeecddeeecddefebdfefebdfefebe0efebe2efeae4efebe2efecd9efecd9efebdfefebe2 +efeae7efeae4efecdbefedd8efecdbefebe0efeae6efeae6efecddefecdbefecddefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7 +eceddbeaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1439bd001eae +00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdff0eddee9e6d7f1ede1f5f1e5e9e7daeae8dbf5f3e7f6f4e8dedcd0eae8dcf5f2e9 +eeeee6e6e3dee5e4e0ede9e8eae9e7e9eae2e8ebe0e8ebe2e8ebe4e8eae5e6ebe5e6ebe7 +e6ebe7e5ebe9e5ebe9e5ebe9e5ebe9e5ebe9e3ece9e5ebe9e6ebe7eae9e4ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2ece9e2 +ece9e2ece9e0ece9e0ece9e0ece9e0ece9e0ece9e0ede9e0ede9e0faf6edefebe2e6dfd7 +eae3dbf5eee6f3ece4eee5deeee7dfefe8deede9deede9deede9deede9deede9deede9de +ede9dee6e2d7ebe7dceeeadff2eee3f9f5eaf5f1e6ede9deeae6dbefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdfeeece0eeece0eeece0 +eeecdfeeecddeeecddeeecddeeecddeeecdfeeecdfeeece0eeebe4f1e8edf1e7eff1e8ed +f1e8e9f1e9e6f1eae4f1eae2f1eae0f1ebdff1ebddf1ecd9f1ecd9f1ecd8f1ecd9f1ebdb +efebdfefebe2eeebe4efeae4eeebe2eeece0eeecdfeeecdfeeecdfeeecdfeeecddeeecdf +eeecdfefebdfefecddefecddefebdfefeae4efebe0efedd6efedd4efecddefebe2efeae7 +efeae4efedd8efedd4efecd9efebdfefeae7efeae7efecddefecd9efecddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddb +eaefd8ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1439bd001eae00119b +001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdd +f1f0dceae9d5eceadbf1efe2ece8ddeae6dbefebe2f3efe4f2eee3f4f0e4f7f3e7eceade +e5e1d8f3f0e9fbf6f2e8e6daeef1d6eef2d1edf2d2edf2d2edf2d4edf2d4edf1d6ecf2d8 +ecf1daecf1dbedf0dfedf0dfedefe2ecf0e2edefe2edefe4eeeee4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0eee2 +f0eee2f0eee2f0eee2f0eee2f1ede2f1ede2f1ede2f1ede2f2ebe1f0e9dfede6def7f0e8 +fff7f0f1e8e1eae1dafbf4ecf3ece2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +eae6dbf1ede2ece8dde9e5daf2eee3f0ece1eae6dbf1ede2efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddefecddefebdfefebe0efebe2efebe2efebe2efebe0 +efebdfefecdbeeeddbeeedd9eeeddbeeeddbeeecddeeebe2f1e8ebf1e7f0f1e7eff1e8eb +f1e9e7f1eae2efebdfefecdbefecd9efedd8efedd8efedd8efecd9efecd9efecd9eeeddb +eeebe2ecece4eeece0eeecdfeeecddeeecddeeecddeeecdfefebdfefebdfefebe0efebdf +eeecdfeeeddbeeedd9efecdbefebe2f1ebdff1edd2f1edd0f1ebdbf1eae2f1e9e7f1eae4 +f1ecd6f1edd2f1ecd8f1ebdff1e8e9f1e8e9f1ebdbf1ecd8efecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8 +ebecdef1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1439bd001eae00119b001bc7 +0837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecddf0efda +edecd7ebead8edebdeefebe2ece8dfeae5dfebe7def5eee4ede7dbefe9dbf0eddeeee8dc +ece8ddf0e9e1e9e5d9edebd2edeccdedeccdecedcdecedcdecedcdecedceeaedceeaedd2 +ececd4ecebd6ecebd7eceadbede9ddede9ddede9deeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadd +eceaddeceadeeceadeede9deede9deede9deede9dee8e1d7f0e9dfeee7dfebe4dcf1e8e1 +f0e7e0eee5def3ece4efe8deede9deede9deede9deede9deede9deede9deede9def3efe4 +f7f3e8f0ece1ebe7dceeeadfede9deede9def5f1e6efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefecddefecddefebe0efebe2efeae4efeae6efeae4efebe2efebdf +efecdbeeedd9eeedd8eeedd8eeedd9eeeddbeeecdff1e9e6f1e8e9f1e8e9f1e9e7f1eae4 +f1ebdfefecd9efedd6efedd6efedd6efecd9efecddefebdfefebdfeeecdfeeecdfecece2 +ecece0eceddfecedddeeeddbeeeddbeeecddeeecdfefebe0efebe0efebe2efebe0eeecdd +eeeddbeeedd8eeedd9f1eae2f1ebdff1edd0f1eecff1ecd9f1eae2f1e9e7f1eae4f1edd4 +f1edd0f1ecd6f1ebdff1e8ebf1e8e9f1ebdbf1ecd6efecdbefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecde +f1ede2f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1439bd001eae00119b001bc70837db +1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeeddbebedd5eff1d9 +edecd8eae8dbf1ede4f1ece6eee6e3eee7e1ebe2d9eee6d9f6efdffcf7e4f9f2e2eee8da +eee6dbf7eee5f5ece5f5ece5f5ece3f5ede2f5ede2f4eee0f4eedef4eedef4eedef5ede0 +f5ede2f5ece3f5ece5f6ebe7f6ebe9f5ece7f4ede3f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f1efe2f1efe2 +f1efe2f1efe2f2eee2f2eee2f4ede3f4ede3fdf6ecfaf3e9f3eae3ece3dcf0e7e0faf1ea +faf1eaf1eae2f4ede3f2eee3f2eee3f2eee3f2eee3f2eee3f2eee3f2eee3e7e3d8e9e5da +ede9deefebe0efebe0efebe0f0ece1f1ede2efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff1ebddf1ebdff1eae2f1eae4f1e9e7f1e8e9f1e9e7f1eae4efebdfefecdb +efedd8efedd6eeeed6eeedd8eeedd9eeedd9f1ecd9f1ebdbf1ebddf1ebddf1ebdbf1ecd8 +efeed2efeed0efeed2efedd8eeecdfeeebe4eeeae9eeeaebeeeaebeeeae7ecece2ebeddf +ebeeddeceed9eeedd9eeedd9efecdbefebdfefebe2efebe2efeae4efebe0eeecddeeedd9 +eeeed6eeedd8f1eae0f1ebdff1eecff1eecdf1ecd9f1eae2f1e8e9f1eae4f1edd4f1eecf +f1ecd6f1ebdff1e8ebf1e8e9f1ebdbf1ecd6efecdbefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeecdfeaeedfebeeddf3e9ddf6e8dff6e6e9f3e7e7eceddbeaefd8ebecdef1ede2 +f6e9e0f4eadeecebd9e8f3f9cfe7ff2747ae1439bd001eae00119b001bc70837db1c60f3 +1e55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeeecdf +ebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff1ebddf1ebdff1ebdff1eae0f1eae0f1eae0efebe0 +efebe0efebdfefecddefecddefecdbefecddf1ebddf1ebddf1ebddf1ebddefebdfefebdf +efebdfeeece0eeece0eeece0ecece0eeece0eeece0eeecdfeeecdfefecddefecddf1ebdd +efecddefecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeeddbe7e9d1f2f5daefeeda +e9e7d8f1ece6f4efebf0ebe7f1ece6f1ede2f5f1e5ebe8d7e4e1d0eee8daf4eee2f2e9e0 +f1e8e1f1eae4efeae6f1e9e6f1e9e6f2e9e4f2e9e4f1eae2f1eae0f1ebdfefebdfefebdf +efebe0f1eae0f2e9e2f3e8e4f2e9e4efebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +eeebe2eeebe2efebe2efebe0eeece0eeecdfeeeddbeeedd9eceed9eeedd9ecedddeeebe2 +eeebe4eeece0eeecddeeecddeeecddeeece0ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2ecece2ecece2ecece2 +ecece2ecece2eeebe2eeebe2eeebe2e9e6dfe6e3dcf0ebe5f8f3edefeae4e9e4deede8e2 +eee9e3edeae3ebebe1edeae3ebebe1edeae3ebebe1edeae3ebebe1f1eee7e9e9dfedeae3 +edede3eae7e0ebebe1f0ede6e9e9dfeeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +eeebe2eeece0eeebe2eeebe4eeeae7eeeae9eeeaebeeeae9eeebe6eeebe2eceddfeeecdd +eceddbeceddbeceddbecedddecedddeeedd9eeedd9eeeddbeeecddeeeddbeeedd9eeeed6 +eceed6eeedd8ecedddecece4ecebe9eceaefece9f0eceaefebebebebece6eaeee0eaeedf +ebeeddebeeddecedddeceddfecece2eeebe4ecebe6eeebe6ecece4ecece0ecedddeceed9 +ecedddeeebe4eeece0eeeed6eeeed4eeecddeeebe4eeeae9eeebe6eeedd9eeeed6eeeddb +eeebe2eeeaebeeeaebeeecdfeeeddbeeecdfecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2 +ecece0eaeee0ebede0efebe0f3e8e4f5e6e9f2e8e7ecece0eaeedfe7ede1edeee6f3ebe0 +f4eadeedeadbe9f2fbcfe7ff2648ac1439bd001eae00119b001ec90130d42165f81b52b9 +e3ecfff0e7def0f3e2e9eedaeeeddbefebdfefeae4f1eae4f5e8dff5e9dbefebdfeceddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1ebddf3eadbf3e7dbf6e9e1f1e6e0efe4e2f5ebe9ece5dfeee7df +eeeadeeeebdaf1ecd8f1ecd6f2edd9f3ecd9f4eddbf4edddf3ecdcefe9dbece8dcefede1 +f2f2e8f2f4e9ebeee5e2e8deeaede2eaede2ebede0ecedddefecdbf1ecd9f2ebd8f2ebd9 +efecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeddbe4e8cdf2f6dbeceed9e4e2d3 +f8f3ede3dedaefece7f3f3ebdde0d5f4faecf0f6e8dde1d3e9e9e1f2edeaede3e4f0e8e5 +e4ecd7f6ffe7dfe6d4eff1e4f1eee7e9e4e0eae7e0ebebe1ecf0e1dde4d2e9f3dbecf4dd +e7ecd6f1f4e1f0eedfe5e3d7ecede7e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8ebede8 +eeede9f5f1eedddad5f6f6ece6e9d8e7ebd2f1f8d6e3edc8ebf2d1eaf2dde7e9e8e8e9eb +f2f5eaedf2dee6ead3e8ebd6ebeee5e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8e9eee8e9eee8e9eee8e9eee8 +e9eee8ebede8ebede8ebede8ebedeaebedeaebedeaebedeaebedeaebedeaebedeaebedea +ebedeae9eee8ebedeae9eee8ebedeae9eee8ebedeae9eee8ebedeae9eee8ebedeae9eee8 +ebedeae9eee8ebedeae9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8ebede8 +ebede8ebede8ebedeaebedeaebedecebedecebedecebedeaebede8e9eee8ebeee7e9eee7 +e9eee7e9eee7e9eee7e9eee7ebeee7ebeee7ebeee7ebeee7ebeee7ebeee7ebeee5e9efe5 +ebeee5e9eee7e9eeeae9edece9edeee9edeee9edeee9edece9eeeae9eee8e9eee8e9eee7 +e9eee7e9eee7e9eee8e9eee8ebedeae9eeeaebedeae9eeeae9eee8e9eee7e9eee7e9eee7 +ebedeaebede8ebeee5ebeee5ebeee7ebedeaebedecebedeaebeee7ebeee5ebeee7ebede8 +ebedecebedecebede8ebeee7ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8 +ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8ebeee7 +ebeee3ebeee5ebedecedebeef2e9eef2e9ecedece8e9eeeae6f5f2e9f4eee3e1d5f8f0e3 +ede4dde3e6f5ddf8ff1a419e133abb001eae00119b001ec90031d42165f81952b9e3ecff +f0e7def0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff1ebddf1e8d7f2e6d8f5e8dff3e8e4f6ecebfcf3f4f9f4f1fbf6f0f0eee2 +f0eedff0eddaefedd8f0ebd8efe9d9f0e8dbefe7dcede7dbf3efe3f3efe4eae8dce4e4da +eaece1eef0e5ecefe4ebede0ebeddfeceddfeeecddefecdbf1ecd9f2ebd8f1ecd9efecdd +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeeddbebefd6f1f5dcf0efddeae6dbfaf5f1 +ebe6e3edece8d6d9d2e9f3e8e5f1e3d4e2d3f8fff8e6ebe5f1f1eff7f0f7e8e7e5e5f2de +d5e9cef1feece7eee6dededef5f3f6f4f2f5efefefe4ebe4f7fff7edfae9dfecdadbe6d5 +e2e9d9f1f3e6eff0e8e7ece8e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae7ebece6e5ea +e1dee5fbf8ffe1e1e3eff2e7e0e8d1e8f3d5e4f1d3e6efdee6f0e8f4f9ffcfd3dcebf1ef +e0e5def6fceeedf3e5e7ece6e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae7ece6e9ece3 +e9ece5e6ebeee7eaf1eee8ecf0e7eaebe9ece6ebeec8dadce4f4f1e8eaddfaf2e5f3e8e4 +e6e7f9dcf7ff1f48a2133abb001eae00119b001ec90031d42165f81952b9e3ecfff0e7de +f0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddf6f1def2eddaf0eadeeae5dfebe7e4e3e1e2e5e4e2e1e2ddebece4ebede2 +ebebdfebebdfedeae1edeae3eee9e6ede9e6f1f0ebe7e7dfe8e8e0f3f0e7eeece0e1decf +e4ded0f1ebdbf2ebd9f1ecd9f1ecd9f1ecd9efecdbefecdbefecddeeecddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecddeef0dbe9ecd9edebdee9e4def4eeeeede9ea +e6e6e6a9afab98a59b83958595aa998fa1917b887e919b939498999aa09e93a599778b80 +8d99979fa6ae9190a0908da29390a59291a3838793929ba2828c8e929c9da1a9ab8e9196 +92919999989e969799949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +94989794989794989794989794989794989794989794989794989794989b9b99a79591a8 +9691af8b899f9ea2a39ea59d939d958f999b9296af8d92af9298a699a0aa9ca2b29295a6 +8b8f9a8d9097949899949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949897949897949897 +949897949897949897949897949897949897949897949897949897949993969990969992 +93989b94979e9b95999d949798969993989b9fb1b3deeeebebede0f5ede0f3e8e4e3e4f6 +d3eeff214aa4133abb001eae00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2 +e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecddedecd7eaecd6eceddfecede5f4f6f3e5e9eaf1f5f6ecf0efe2e7e3e2e7e1e6e8e3 +e7e9e4eaeaeaeceaededeaf1eeebf2e8e9ebe4e6e3e7e8e2f2f2eafcf8ecfdf6e6faeede +f9ecd9f6e9d6f5ead6f3ebd8f2ebd9efecddeeecdfecece0ecece0eeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecdfeeefdfe5e6d8f0ebe5ebe6e3ede7ebebe9eee4e5e7 +8c9793f4fffad9f2dfecfff3edfff4e6ffecf2fff8e0f0e6f4fffdf0fffbf0fffdf4ffff +f7fffff0f3fffefcfffefcfffefcfffbfefff9fffff5fefff6fffffbfffff9fbfffdfbff +fffdfffefffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffefefffefdfff9f7ff +fcfdfffbfeffeaeffff4f9fff7fbfff4f4fff7f8fff5fbfff2fbffe1e7fff8fefff9ffff +f9fdfffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff859799deeeebebede0ede5d8f4e9e5e5e6f8cee9ff +224ba5133abb001eae00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2e9eeda +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdd +e8ecd5e8f0d8eaf1e1e8f0e5f2f8f6d4dcdee8f0f3dfe9ebe9f1f3e9f2f1eaf0f0e9eef1 +e9ecf3eaeaf6eae7f8e9e8f6e1e6ecf2f8f8eff1eed9d8d3dbd7ccf6ece0fef1e0eedfcc +f8e9d6f8e9d6f5ead8f2ebdbefebdfecece0ebede2ebede2eeece0efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff3f1e5ebe7def7f2eff0eaecece5eceeebf2e8edf0899893 +ecfff64869546e957a3f684a72997c6789707b9b866b8874698b724969526880737f8f8c +798289808490f4f6fff0f2fff5f9ffeff6fef8fffff5ffffe7ecf0fefefffffdfffcf9ff +fefffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffff0f7eff7ffedf9fffd +f8fcfff3f4ffc4c5ffb6b3ffc5bfffb0acffc0c5fff5fefff7fffff4fefff1fbfaf9fffd +fbfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff849698e4f4f1eef0e3ece4d7f9eeeaecedffd2edff244da7 +133abb001eae00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2e9eedaeeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfecedddecf1db +edf7dfe9f4e4e0eae1e3edecb7c1c3d4dfe3ccd7dbbcc6c8b9c3c5b7bfc1b4b9bdafb2bb +acabb9a9a6b9a6a5b59b9fa89a9fa29ea2a3a6a6a4aca9a4beb7afe0d8cdfff7ebf3e9dd +f3e9ddf2eaddf1ebdfefebe0ecece2ebece4ebede2eeece0efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1ede2ede6e0f9f0f1f0e7ecebe4ecebeaf0e5edef8d9e98dcfbe9 +70987d305f3d63956f2e603a6c9b77d1fddc7aa3812d57315f85604f6d53f1fff7f5fffd +8a9294000105fbfffffbffffebf4f3f6fffdf9fffffafefdfefffffdfafff6f3fafcfdff +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfbfffdebf5ecf9fff4f8ffffb0adff +b6b1ff1e1c8a08077c1b17a00a078a141778b0b3ffbfc4fff5fcffe1eef6f7fffbf9fffb +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefdfafefd +fafefdfafefdfafefdfafefdfafefdfafefdfcfef9fdfef6fcfff8f9fefffafdfffffbff +fffafdfefcfff9feff899b9de4f4f1eceee1ebe3d6f7ece8ecedffd2edff214aa4133abb +001eae00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2e9eedaeeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddde5e9d8eaf3e0 +e9f3e8e3ece7edf7f8c3ccd1f5fefff5fefff9fffff9fffff9fffff5fafdf3f4f9f0eef9 +edebf9ebe9f6f7f8fddee2e5d9dde0e5e9ecd9dde0bcc0c3c0c1c5dbdcdeeaebedebebeb +ecebe9ecebe7eeebe4eeebe2eeece0efebe0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff0e9dfeee5def5ebeaede2e6eee7eeeae9eedfeae68ca296e9fff4366543 +ddffe81e592967a3702864316fa778295f2e6d9f6c487645648862e2fce1f5fff67a857d +fbfffd000200eef4f0f9fffbf6fff7f9fffafcfffbf1f1effffefffffefffffffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffcfffff1f8fef8fffff7fdffb8b9ff1509b51b0fc7 +04057b1217730205702524a30f0ba00e08a8160fadbebafff4fdfff3fffffbfffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8c9ea0deeeebebede0eee6d9f4e9e5e7e8fad1ecff1e47a1133abb001eae +00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2e9eedaeeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfe7ebdcedf3e7ecf1eb +e1e7e5e8f0f3bcc3cbf8fffff9fffffbfffffbfffffcfffdfcfffdfffffffffefffffdff +fffdfff9f7fafefffffbfffff4fdfff0faffe8f6ffc0d1e191a2b2ddeefee0eefbe4edf6 +e7ecefebece7efebe2f2eaddf2ebdbf1ebddefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f1ebdff5ede2f2e9e0f6ebe7efe5e6f6f0f2edefeeddeae38fa797e5ffefdfffe92a6633 +d2ffdb2a6e3360a4671e5d2464a1682c632a659764e9ffe6eeffedf4fff6000400000301 +060a09090f0bebf5edf9fffbf6fdf6fcfffdf0f0f0fffefff7f5fafffffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffcfffff9fffff1f8ffb6b8ff1b159b0600c60a00c6f0f3ff +eef7fff0f6ffe2e4ffeae6ff1a12ca0700c80900a9c9d0ffecf8fffbfffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff90a2a4ddedeaeff1e4f7efe2f6ebe7e7e8fad5f0ff224ba5133abb001eae00119b +001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0e9e9dfeeefe9ebebebe9eaee +e9ecf3bfc2cbfbfffff9fefffcfffffcfffafefff8fffff6fffff8fffffafffefbfffefb +fffcf8fffffbf4f9fdf5ffffebffffc4dffab7dafa9fc3e57093b3cbeaffe2f9ffe5f3fc +e9edece9e5dafef1e0ecdfccf2ebdbefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdd +f1ead8f5ecddf4eae1f1e8e3f2edeae8eae5e5f2e887a38de6ffeddfffe6d7ffdd1c6122 +d6ffd81d621f70b370266629639c67dfffe7e5ffededfff6effffaedf7f8fbffffc3c6cd +000209fbfffffbfffffafffff9fcfffffdfff7f3fffffcfffffefff4f6f5fefffff7f9f8 +fefffff6f8f7fefffff6f8f7fefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffcfffbeffbeff5ffffbbb8ff140bb40900bff0eaffe6ecff16226c +040c6f0f1585e7ecfff0edff0b00d40d02c2b6bdfff4fffffbfffffefffff9fbfafeffff +fafcfbfefffffcfefdfefffff6f8f7fefffffeffffeff1f0fefffffcfefdfbfdfcfeffff +fefffff9fbfafefffffefffffbfdfcfefffff1f3f2fefffffbfdfcfefffff4f6f5feffff +fafcfbfefffffefffffbfdfcfefffffcfefdf7f9f8fefffff6f8f7000100fdfffefdfffe +fafcfbfefffffefffffefffff8faf9fefffffefffffdfffefefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc8 +0030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebe0ede8e2f1edeaeee9edebe8efeceaf5 +c0c0cafefefffcfdfffefffdfdfff7fefff3fefff2fffff3fffff3fffef5fffdf7fffff6 +fffffbf2f7fbe2f2ffdbf7ffcbf2ffabd8ff7aabd67faed86890b4c5e5fee1f4ffedf3f3 +ece5dbfff3defdedd6f2ebdbefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf1ead7 +f5eddaf4eadef1e8dff2ede9e8ebe4e5f3e689a28ce4ffe9dcffe02e6b306eb070296c27 +d8ffd427692257955429622d6b9e73446d4de7fff0f4fffff9fffff9fcffc7c7d1000007 +fcffffeaedf203060b00000700000902000d01000bfbfafffefffffeffff020403f8faf9 +f8faf9fbfdfcfefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffcfffaf7ffefb9c4e0140fa10100c01103d20600aae8f1ffe2f0ffedf5ff +edf3ffeef3ff05059b0e00de1004d215187fb3bce3f8fcfff0f2f1fefffffafcfbfeffff +e4e6e5fefffffefffffefffff0f2f1fefffffefffffefffffefffffeffffe2e4e3feffff +fcfefdfcfefdfdfffefcfefdfefffffefffff6f8f7fefffffdfffef8faf9fefffffeffff +f4f6f5fefffffeffffeceeedfefffff5f7f6fefffffbfdfc000100fefffff7f9f8feffff +fbfdfcfefffffcfefdf7f9f8fefffffafcfbfefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d3 +2064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebe0efe7e4f3eaebf1e8edeee7efeee8f4c0bdc8 +fffdfffdfefffefffdfefff8fefff4fffff3fffff3fffff4fffff6fffff8f7f3eafcfbf7 +f8ffffefffffddfcffbee8ff7babd9467aac5386b56794bd456783d0e6f4ebf3f5eeeade +f0e1caf7e7cef2ebd9efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdbf0ebd5f4eed6 +f3ecdaf0eadef2ede7e9eae4e6f2e68aa18de9ffed38673b669f681c581c6eaa6a195613 +dfffd641793a5e955c386a395b845ce8ffe9f5fff8fbfffdf2f4f3cacacc070707fbfdfa +fcfffd000200fefffffffffff4f1f8fffefffafafcf2f2f2090909000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcfff8eefee4bfc9ec0a00ae2b18ff0b00ea160bd1161d85edfaff0d138fd4d8ff +2121c10000a70e01e70d03d609098bc4c9fffbfdfffbfbfbfbfbfbfffffff3f3f3ffffff +fffffff9f9f9f3f3f3fffffffdfdfdfdfdfdeeeeeefffffffffffffffffff5f5f5f9f9f9 +fffffffffffff1f1f1f7f7f7fdfdfdfffffffcfcfcfffffffffffffcfcfcf9f9f9ffffff +fffffffdfdfdfffffffffffffbfbfbf8f8f8ffffff000000eaeaeafffffffffffff5f5f5 +fffffffffffffefefefffffffffffff3f3f3ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f7 +1851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebe0f0e9e3f3ebe9f1e8ebefe8efeee8f4bdbac5fefcff +fefffff9fdfcfafff9fafff6fafff6fcfff6fdfff9fdfffcfdfffcfffffbf0f4f3f5ffff +e8feffdafaffbfe7ff88b5df7babd96692bf7199bd597992718492e8f1f0f6f4e8e3d8c2 +fffbe3f2ebdbefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdbeeecd3f3efd6f2edda +f0eadef2ede7e9eae5e9f0e98d9f91ebfff1648e682657286ba06a295f2570a368316029 +d4ffca34672c689961567d50eaffe4f3ffedfcfff6fffffabfbeb9010100f5f7ecfcfff2 +000300fefff6f6f7effffffbfbfaf8fffffffffffffdfdfd060606f4f4f4ffffffffffff +f8f8f8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffaf7fff1bac2f02518d70000d80f00e7120cc4d4dbffedf8ff131b98ebf0ffecedff +1916c50900df1409e30c09a0b2b4fffbfcfffffffff8f8f8fafafa000000010101000000 +000000fffffff4f4f4000000060606151515e4e4e4fefefef2f2f2151515000000060606 +f3f3f3ffffffffffff000000000000000000ffffffffffff0e0e0e000000000000fafafa +f6f6f6ffffff000000000000000000ffffff0000000d0d0d000000000000fbfbfbf1f1f1 +fcfcfc000000050505000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff1eae0f3ece6efeae7eee9edeae9f1b9b9c3fafdfffbffff +f9fffff8fffff8fffff8fffff8fffff9fffff9fffff8fffff8ffffdfedeee2f3fae0f6ff +e5ffffe4ffffc5e6ffcaedffcfeeffc2ddf89aafc066757cd4dddae4e6dbf0ebd8f2ebd8 +f1ebddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdbeeecd5f1efd6f2ecdcf0e9df +f2edeaeae8e9eaeeed909d96e9fff1486a4f78a07d2d572f79a27632592c7a9d73416736 +e2ffd63363255c824f455f38ebf8defeffeffffff3c8c4b8070500ffffeffeffed050a00 +000400060900010100fffff8f5f5f3ffffffeeeeee000000fffffffbfbfbffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +f7fffda8aeea0500ba1f0df51b12c3e2e5ff0f167eedf7ffe1e8ffdde5ffedf9ffeaf1ff +160cdf0100d7120db2bebefff6f6ffffffffffffff000000fffffffffffff3f3f30a0a0a +f4f4f4060606fffffffefefefbfbfb0d0d0dffffff050505fdfdfdffffffededed0d0d0d +ececec000000fffffffafafaffffffe2e2e2fffffff5f5f5fffffff8f8f8131313fdfdfd +000000ffffffffffffffffffeaeaea151515f4f4f4ffffffffffff131313ffffff000000 +fffffffbfbfbffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff0eddef0ece0edeae3ececece8e9eeb3b7c0f5fcfff7fffff5ffff +f4fffff4fffff4fffff4fffff3fffff3fffff1ffffdceef8e6fbfff0ffffe5fbffdef1ff +e3f5ffdff1ffe2f4ffd5e6f8e6f4ff79838c788283eef4f0eef4eaf1f3e5dddeceeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefecdbededd5f0efdaf0eddef0e9e3f2ecee +ece7eeecedf2919b9ceefff9e2fdecebfff4dcfde07f9e7ff0ffece1f8db77926f47723d +628f583d61357e9676000500e6e6dafffef8d1cac4040000deded2fffff3fefff1fdfff2 +f8fceefffff8010000fcfcfaffffffffffff000000fffffffffffff0f0f0ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffff6ffff +b6bbfb1609bb1606da0b04acf0efffeef2ff0000660b15761e2a80edfbffdde4ff0a01ce +0f03e1120db1c2c2fffbfbfff1f1f1ffffff000000fffffff7f7f7ffffff000000ffffff +000000000000000000000000000000ffffff000000f1f1f1f8f8f8f7f7f7060606ffffff +0b0b0be8e8e8ffffffedededfffffffcfcfc0000000b0b0b0d0d0d000000ffffff000000 +f4f4f4ffffffedededffffff030303f7f7f7efefeff7f7f7000000ffffff000000000000 +000000000000111111ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddefeedaedefdaeaecdfebede8e5eaedaeb7bef2fcfff4ffffb9c9d6b8cad8 +b6c9d8b5c7dbb4c6deb3c4e2b2c2e4afc4e3b3cedfbad6e1afc7d1a5b9c2a0aeb7a6afb8 +bbbfc8c0c1c6b3b2b7a3a1a2a1a19f676964eff4ede4ebe3dde7dcf8fff3ecece0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefecddedecd7f0efdbf0ece1eee9e6f4eaf3ece6f2 +edebf89498a1f5fffff1fffff0fffbf0fff6748976f2fff1f1feedf4fff1dfffe3001000 +edfff4e7f9ed131718fffbfffff9ffc4b8c60b040cfffdfff7f5f8ffffffecedf1feffff +fffeff000007ffffffefefefffffff070707f8f8f8fffffff0f0f0ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffff8ffffb7bdf9 +1711991004be0000c01307d3eeecffeef3ffedfbffcedcffedf2ff1f1dc00700cd1105d1 +120ea0b1b3fff2f3ffffffffffffff060606f2f2f2fdfdfdffffff020202ffffff040404 +fdfdfdf6f6f6fffffffbfbfbfdfdfd060606ffffffffffffffffff000000ffffff030303 +fafafafffffff9f9f9ffffff000000fffffffdfdfdf0f0f0040404ffffff000000ffffff +fffffffefefeffffff000000ffffffffffffffffff050505f5f5f5090909ffffffffffff +ecececfbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecddf0efdaedefd9eaeddcebeee5e4eaeaadb6bdeffcfff1ffffe4f9ffe1faffdffaff +ddf7ffdcf5ffdbf1ffdaf0ffd9f0ffd5f0ffb9d5e39cb7c2cce0e7f5fffff3f7faeeeaeb +d3c9c8ddcfcee7dcd8dad5d1bfc0ba8186827d8681d6dfdceaefebecece4eeece0efebe0 +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0efebe0 +efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecddebecdaeeefdff2ebe3f0e7e8f4eaf3ece6f2ececf8 +9498a3eaf3faf7ffffe9f9f6f2fffd77887ef7fffafcfffaf6fff3f0fff3dffbe5000a01 +00040600000efffafffff6ffd1c3da060009fffbfffffeff000000fffffff8f7fdf7f5ff +0b0914faf9fefffffffefefe000000fffffff6f6f6fffffffbfbfbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefffff8fcfff8fbffb7b2ff +140dab1107e10000dd0c08ce090aa0e5ebff1a1f7a110fae0000c20f0bdc0000aec2c2ff +f8f8fffcfdfffffffff6f6f6000000fffffffffffffafafa000000f7f7f70a0a0af8f8f8 +ffffffffffff000000ffffff000000fffffffbfbfbfbfbfb040404ffffff040404f9f9f9 +fdfdfdffffffebebeb0c0c0cfcfcfcefefefffffff000000ffffff000000fffffffbfbfb +fefefeffffff020202f8f8f8fcfcfcffffff010101f8f8f8090909f4f4f4fcfcfcffffff +030303ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9 +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdd +edecdaf0efdbeceed8e9ebddeeeff1a3aab0f4fffff0ffffadc6e4b0cef2a6cae4b1d5ef +a7c8eba5c1e6b8d1efb2c8e0abbacfb5c5d5eeffffd8ecf3b5c4c7a3a9a9afa5a6b4a2a2 +c1afada49695aca8a59b9f9eced6d891969c93919cece6f0fbf7f6e2e2daefece3f3f3e7 +e7e5d9f4f2e5e3e1d4faf8e9efecddefecddefebdfefebdff1eae0f1eae2f1eae2f1eae2 +efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecdfeaecdeeeeee2f4e9e5f4e6e6f2ecf0e9e8eee9eef49299a1 +fcfffff0f3faf8fffff4ffff728780f5fffdf8f9f4fffff8f4fbe9171f10f0f4f5f2f2fe +010015fff9fffff7ffcbc0d1060002fffbf2ffffeeffffed010200000200030303feffff +ffffffe8e8e80a0a0a070707000000fffffffefefef8f8f8ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfcfef0fefeffc8c0ff0d0889 +060cc60004de0000df0e0ad0f5e8ff1205910700c60000d60c19e1000ea2babdfffffcff +fffefff0f0f0ffffffffffff000000060606000000000000ffffffe8e8e80a0a0a070707 +000000fffffffefefef8f8f8070707010101000000fffffff8f8f8f6f6f6181818000000 +000000fffffffafafa0000000404040a0a0a000000fffffffdfdfd060606010101000000 +ffffff0a0a0af1f1f1ffffffffffff000000fffffff1f1f10d0d0d000000000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfedebde +efeedceeedd8eaebdbeeeef0a4a9aff2ffffeeffffd9f6ffd1f2ffd6feffc6eeffcbedff +dcfaffc5e1f9bbd0e3d9e1f4eff8ffbaced79fb7bbcce0e1edf7f6fffdfdcbbdbde2d4d3 +dbd3d1d3d9d7b8c6c66f7e81bbc8d0a3a2b2736f7dd6d4d5fffffae1e1d9fcfcf2e7e7dd +f0f0e4f2f0e3eae8d9efecddefecddefebdfefebdff1eae0f1eae2f1eae2f1eae2efebe0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfedebdff1ede2f3eae3eee9e5edefece5ebebe9eef197989dfffbff +fffcfff2f7fbf5ffff7c918ae6f5eefffefbfffbf9fffff800010009080d0b0916090619 +fcf7ff110a1ac9c2ca0b0602fcf8ecffffedfefde8fffff1fffff6f0f2effbfcfef6f6f6 +fefefefefefefffffffbfbfbffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff3f8f3f7fff7ffb8b5ff0f1c9f +0006b30000d0110cdafce7ff0c008b241ad10208c0000ca4afc6fff9fafff9f2faf2f0f3 +ffffffeeeeeef8f8f8fffffff6f6f6ffffff000000f6f6f6fefefefefefefffffffbfbfb +fffffffffffffffffff3f3f3f9f9f9f9f9f9fffffff9f9f9fdfdfdfdfdfdffffffffffff +eeeeeefffffffbfbfbf3f3f3fffffff3f3f3fdfdfdfcfcfcffffffeaeaeaffffffffffff +fffffffffffff8f8f8fdfdfdfffffffdfdfdfffffffcfcfcf5f5f5ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfedeede +eceed9eaecdeecedef9fa6aef0ffffedffffc4e1ffabccf5c4e9ffa9cee8b4d5f8c3e0ff +9ab4cbb0c3d2f8ffffa7afbcb9ccd2e6ffffeeffffeffffff9ffffd7d7d7f4f4f4f9ffff +e6fcf9b7d7d2cceeed6d8b8d96a7af888f978c8e8ddad9d4e7e6e1eeeee6e8e8deebebdf +f4f2e5e6e4d7efecddefecddefecddefebdff1eae0f1eae0f1eae0f1eae0efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff2eadff5e7dcf5ebdfeceee0e3efe1e1f5e9dfeee7eceeed9e959afff4fefffaff +fcffffeefdfa7a8d87c1ccc6d1c7c6cbbcbfcecbd2c9ccd3bec1c6bdc1c2c3c8c4b7bcb5 +000200caccbf050500fffff6fbfbf3f2f1edfffffdf9fafcfcfffffcfffffefffffefefe +fffffffafafafffffff8f8f8fdfdfdfbfbfbffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffefffff9fffffbfff0e7fafcfbffeefdffb7c9ff +060eae0d09b51000862916890d0773bac3ffaec7ffe2f9fffcfafffff8fffffdfffbfbfb +fffffff5f5f5030303000000000000fffffffffffffefefefffffffafafafffffff8f8f8 +fdfdfdfbfbfbfffffffffffffffffffefefefffffffffffffffffffafafafefefeffffff +fffffffffffffffffff9f9f9fffffffffffff8f8f8ffffffffffffffffffefefefffffff +f5f5f5fffffff6f6f6fffffffffffffafafafffffffffffff0f0f0fefefeffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfecece0eceee0ebecda +eaecdfe9edf09ba2aaecfcfcecffffcbe8ffaecef5c7ecffbce2f9c5e3ffb5cff0aec7dd +edfdffcfcedcacacb6f3fffff0ffffe3fdfcf0fffff7fffff3fbfee7f1f3f2ffffc9ece8 +8db7b355827fb0d8d76e8a8d98a7ac696d6e7a7975fefdf9e0dfdaeeeee6ebebe1e7e5d9 +f2f0e3efecddefecddefecddefecddf1ebdff1ebdff1eae0f1ebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f2eaddf5e8d8f5ecdbe9f1dce0f1dee0f7e5def0e4eceeeb9e9598fffafffff9fff9f9fb +eef7f489968f00020007000011050701000505080f070b0a0b1308000600061200000600 +010900000300fbfcf6faf8fbfffefff0f0f8fcfffffbffffeff4f8f6f7f9fffffffefefe +fffffff8f8f8fffffffffffff7f7f7ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffefffffbfffffbfffffafffffafff7fffff0feffafbbff +c1c3ffc4b9ffcfc1ffc7c4fbe5eefff0fffff0fffffffbfff8ebfff7f4fdfffffffafafa +f7f7f7fffffffffffff6f6f6f3f3f3f7f7f7fffffffefefefffffff8f8f8ffffffffffff +f7f7f7fffffffafafaebebebfffffffdfdfdfffffff6f6f6fffffffffffffffffff9f9f9 +f8f8f8fbfbfbffffffffffffe6e6e6fffffff8f8f8fffffff7f7f7fdfdfdfffffffdfdfd +fffffffffffff6f6f6fffffffffffff2f2f2f9f9f9ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0eceee3eaede2eaeddceaede2 +e8ebf0969fa8e8f8f8ebffffbfd9fcb5d5fcb9ddf7bce0f6bfdcfc98b1cfc0d7e9ebf5ff +b0a6affffafffcffffecfcfcf0ffffedfffff5ffffecf6fff4ffffcee7eb8ab2b20d3e3b +447571cdf7f59fbdbf5e6d708c90934d4b4ce2e1dfedece8efefe7f1f1e7e4e2d6f7f5e8 +efecddefecddefecdbefecddf1ebddf1ebddf1ebdff1ebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdb +f0ebd7f1efd8edefd9e7efdae7f4e3e1efe2e7f1e9959a96f9f7fafffdfffffdfffffeff +eceeebfefefcfffbf8fef9f5fffffae5e5dbfefff3e5edd6f9ffeaf9ffeaf2fee6fbfff1 +f9fcf5ffffffefecf3fffdfffefefff3f5fff6fdfffbfffffefffff9f9f9fffffff4f4f4 +ffffffedededffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffefffdfcf8f9fff3fdfff3ffedebeef8fffff1ffffe6f2ff +fbfbfff2ebfffffbfffffefff9fff3fbffeffffefbfffdfffffeffffffffffffffffffff +f6f6f6f9f9f9fcfcfcfffffffffffff9f9f9fffffff4f4f4ffffffedededffffffffffff +f8f8f8fcfcfcfffffffbfbfbfffffff8f8f8fffffff6f6f6fdfdfdf2f2f2ffffffffffff +fcfcfcf8f8f8fffffffdfdfdf7f7f7fffffffffffffffffffffffffefefefafafaf4f4f4 +fdfdfdffffffedededf9f9f9fffffffffffffffffff2f2f2ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc8 +0030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeece0ecede7eaede4e9eddee8eee4e7eaf1 +929aa5e5f4f7e9ffffc3ddffd3f0ffc0e2fbbee1f5c1defc9eb6d2daefffbcc3cdebd8de +fff8fbfefafbf4fefff2ffffeeffffe1edf9f4ffffe9f9ff95adb720474c5a8888b0dcdb +d0f4f4cfe4e7717c80a6a7ab5a585b817f80f7f6f2e4e3def0f0e6edebdfedebdeefecdd +efecdbefecdbefecdbf1ebdbf1ebdbf1ebddf1ebddefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeddbeaeed5 +eef1d6f2edd9eeebdaedf1e2e3ede2e5f2e9919c96fcfffffafbfffafbfdf0f6f6ebf6f2 +0d18140001000905000801001914000404000a0d00010a00edf6e3fbfff6fbfffaffffff +fffefffffdfff5f2fbf7f7fffcfffff9ffffedf5f7fefffff7f7f7ffffffffffffffffff +fbfbfbfffffff7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffefffdf7fef6fffffa9e8a93aa939b92878186878165747b7f8f9c757b87 +8f8d98867f868d867e9c9d7ee6eac7ffffeffcf9f2fffffde8e8e8fdfdfdffffffffffff +f7f7f7fefefefffffffffffff7f7f7fffffffffffffffffffbfbfbfffffff7f7f7ffffff +ffffffffffffecececfffffffcfcfcfffffffbfbfbfffffffffffff7f7f7ecececffffff +ffffffeeeeeefffffffffffff8f8f8f8f8f8f9f9f9ffffffeaeaeaffffffffffffffffff +fbfbfbfffffffcfcfcfffffffdfdfde1e1e1ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d3 +2064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeebe2eceee9e7ece6e9ece1e9eee7e6e9f29098a5 +e2f1f4e8ffffc6deffd3f1ffc2e5fbbfe0f3bfdaf7a4b9d4e8faffa2a5acfff1f6ffe9eb +fffcfbf3f7f8d4e1e7f4fffff2fbffe7edff97a2b62033445c7a85b6d8e1b7d6dbedffff +e8edf3918e9599979c7a787b4a4849eeedebe4e3dfebebe3f1eee5e7e5d8efecddefecdb +efecdbefecd9f1ecd9f1ecd9f1ebdbf1ebdbefecddefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddbe6f0d5ecf2d6 +f6ebd9f7e7daf2eee3e6ebe4e3f2eb8e9d9afbfffff2fafdf1ffffeaffffe4ffff000a04 +fbfffff7ecdaf7e8a7ffffb5eee4a9ffffdb0a0800000002fefefff4f1fffffbfffaf2fd +fffafdfffefbfffefafafffbf1faf7f9fffff6f8f7fffffffffffffbfbfbe9e9e9fefefe +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcfffff8fffff8fdf97a6a6af1d9d5ebd9cbf3ece2e2ebf0dcecfbe3ecfde2e4f1 +d7d1d3f8eee2afaa8a5e5b3afefff1fafbf6fefefcfdfdfdfffffffffffff6f6f6ffffff +fffffff1f1f1f7f7f7fffffffffffffbfbfbe9e9e9fefefefffffffffffff3f3f3fafafa +fffffffffffffffffffafafaf4f4f4fffffff8f8f8fbfbfbfffffffffffff7f7f7ffffff +fffffff3f3f3fbfbfbfffffffbfbfbfffffff5f5f5fffffffffffff0f0f0f6f6f6ffffff +fcfcfcfafafaf3f3f3fffffffffffffefefeffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f7 +1851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeebe2eceee9e7ece8e9ece3e9eee8e6e8f48e96a3e1f0f3 +e8ffffbbd3f5b6d2f9b7d7eeb8d9eab2cce796aac3e0f0fda4a7acead4d6fff7f6f6f1ee +f9fffff0ffffd8eaf6a0adc0616b84323e563d4f658faabb9cbac5c0d8e2d7e4ecd7d1db +aea2ac8f8a90989699615f62e9e8e6f6f5f1ebebe3ece9e0e9e7daefecddefecdbefecd9 +efecd9f1ecd9f1ecd9f1ecd9f1ebdbefecddefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddde6f0d7ecf1daf9e9dc +f8e5def2ede7e6ebe5e6f0ef94999dfff9fff8ffff000e0900190b001b0900160a000007 +fff9e8ffffadf8dc78ffffb6f4e7ba070000fffbff010013fffafffaeefffff9fffffbfb +f6ebe5fffff4f8fbf0f9fffaf9fffbfefffdfbfbfbfbfbfbfefefefffffffffffffefefe +f1f1f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fbfffff0fffff8ffff8e847afffce8fffde3fdf2defbfffff2fffff2fffff7fffffffff8 +fff7e69c9579ffffea474946fbfffff9fafcfffffffafafaf7f7f7ffffffe9e9e9ffffff +fafafafffffffbfbfbfbfbfbfefefefffffffffffffefefef1f1f1fffffffffffff5f5f5 +f5f5f5fffffffffffffffffffdfdfdfffffffffffff9f9f9fbfbfbfdfdfdfefefeffffff +fefefefcfcfcf8f8f8fffffffcfcfcfdfdfdf9f9f9fbfbfbfffffffbfbfbfffffff9f9f9 +fffffffffffff6f6f6fdfdfdf5f5f5ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80334d71c60f31e57be +dee7fff4ebe2edf0dfeaefdbeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeebe2e8eae7e7ece8eaede4e5eae6eaecf8818996e5f4f7e7fbff +cce3ffcbe7ffcbebffb9d8eabdd5f1aec2dbbbcbd8acb4b6c2b8b6dcd3ccf8fffbe2f8f5 +dcfbfde3ffff7d94a6a0b4cc30415b283e55294658203e499cb2bddde5f0897f8a968691 +8780879896995c5a5decebe9f6f5f1e9e9e1f2efe6e6e4d7efecddefecdbefecd9efecd9 +f1ecd9f1ecd9f1ecd9f1ebdbefecddefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddeaeddaf0efddf7e9e0f2e7e1 +eaf1eae2ede9edecf2a092a1fff3fffbfeff00180e5ad5b90792716bccb8070311733e36 +764800ffff93ffea97fff4bf110600fffcfffdf6ff030012fff9fffff2fefffafafffcf3 +fffef1fdfeeefbfff4f4fef3fefffdfffffffefefef9f9f9fffffff5f5f5fffffffafafa +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffff +f1fffff4ffff7f7e69ffffd8fffad1ffffdffefff4f2fffee5f9faf2fffffcfff1faf8e3 +afa79a4f49495c6174434a5df3f6fdfffffffffffff9f9f9fffffffafafafafafaffffff +ffffffffffffeeeeeefffffffffffff7f7f7fffffffafafafffffff3f3f3fffffff4f4f4 +fffffffffffff1f1f1fffffffefefefffffffafafafcfcfcfbfbfbfffffffffffffcfcfc +fefefefffffff8f8f8fcfcfcfffffffffffffdfdfdf7f7f7fffffffffffff9f9f9f9f9f9 +fffffff8f8f8fffffff6f6f6fffffffafafafffffff6f6f6fffffff8f8f8fffffffdfdfd +fbfbfbfcfcfcfffffff9f9f9fffffffdfdfdf3f3f3fffffffffffff1f1f1ffffffffffff +fffffffffffffafafafefefeffffffe4e4e4fffffff7f7f7fffffff8f8f8fffffffefefe +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80334d71c60f31e57bedee7ff +f4ebe2edf0dfeaefdbeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeebe2e9e9e7e9ebe8eaede4e7e9e6e9ebf7818795e5f3f6e6faffb6cdef +b2cef3b9d9eeafcee0b5cde79fb3ccd6e6f3a0abadf5fcf5eaf6ecdbf9efe3ffffc5f6f2 +d1ffffb9ddeb39586c5e7a90adcce1b3d7e7aaccd8bfdae3e8f5fefcf4ffbfb2bc878087 +969497575556e4e3e1e9e8e4eaeae2f7f4ebf0eee1efecddefecdbefecdbefecd9f1ecd9 +f1ecd9f1ebdbf1ebdbefecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfedebdef3ede1f9e7e3f2e7e5e8f1ec +e1ededf0eaf6a58fa4fff2ffe9ecfd002417008a6b45eac20b7d6401000cffebeafff4ab +f0c964ffffaffff4b907030000020017181a000007060005fff9fffff9faffefebfffdf3 +fdfbeefcfff3fbfff6f6f8f3f9f9f9fffffffffffffffffffcfcfcefefefffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffe9faff +e2f3fd9a9e8ff7f1d9917f71958383847e8a787e948192ae8293ad7e8796818090867c97 +100a26abb3ca5b6777fcfffffffffff3f3f3fffffffffffffffffff6f6f6fffffff1f1f1 +fffffffffffff4f4f4efefeffffffff3f3f3fffffff6f6f6fffffff5f5f5fbfbfbffffff +f5f5f5fffffffbfbfbffffffdfdfdffffffffffffff5f5f5f4f4f4fffffffffffff4f4f4 +fffffff2f2f2ffffffffffff000000fffffffffffff9f9f9f7f7f7ffffffffffffffffff +fffffff4f4f4fffffffffffffffffffffffffffffffffffffffffff5f5f5fffffffefefe +fffffffffffff5f5f5fffffffffffffffffffffffff2f2f2fffffffefefeffffffe9e9e9 +fffffffcfcfcfffffff8f8f8fffffffffffffffffffbfbfbfdfdfdffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001dc80334d71c60f31e57bedee7fff4ebe2 +edf0dfeaefdbeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeebe2eaebe6eaeae8ebece4e9eae5ebebf7808392e2f0f3e5f7ffd5ecffcae6ff +ceeeffbfe0f1bad4ed92a8c0dbedf9879b9cc8e2d9dbfff3c4f8ebbefef0bbfef5c4ffff +c5faffc6f4ffb2dcecb6e0f0c6f4ffbde9f2a6cbd1eeffffe7eaf397919bb2b0b58c8a8d +626061f2f1edf4f3eeeeeee4eceadeebe9dcefecddefecdbefecdbefecdbf1ebdbf1ebdb +f1ebddf1ebddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecdfebecdef1ede2fbe6e5f7e4e6edefeee3ebee +edebf69f92a4fff4fff7ffff001c1056e1c400967066d6be00010efff0f3fff2c0fffeb3 +5b4d06ffffc6d5e7adf4ffdde8fddef7fff30e0f09f5ebecfff8fe1d080d0a00000b0602 +020500000400fefffdffffffffffff050505f1f1f1fffffffbfbfbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff2fffff2ffff +737a80fff9ffac90cd11003cd0b8ff1a0e6000005a00036400026303005e2b1e7a000037 +f5ffff31403bfafefdfcfcfcfffffff8f8f8f8f8f8f6f6f6fffffff3f3f3fffffff5f5f5 +fffffffffffffffffff7f7f7fffffff1f1f1fffffff7f7f7fffffffffffffffffffefefe +f3f3f3fdfdfdf2f2f2ffffffffffffe9e9e9fffffffffffff7f7f7fcfcfcffffffffffff +fafafaffffffeeeeee101010fbfbfbf4f4f4fcfcfcfffffffafafaf6f6f6ffffffffffff +ecececffffffffffffddddddfffffffffffff2f2f2fffffffefefefffffffffffffbfbfb +efefefffffffffffffffffffefefeffffffffefefeffffffeeeeeeffffffffffffffffff +f4f4f4f7f7f7fefefefafafaf8f8f8fafafafffffff3f3f3fcfcfcffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001dc80334d71c60f31e57bedee7fff4ebe2edf0df +eaefdbeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeebe2ebeae6ebeae6eeebe2ebeae6ebe9f67d7f8edfeaeee3f5ffaec4e9a6c2e9afcfe6 +abccdfa9c4df8ba1b9bbcedc8da5a7cdede8c8f6ecccfffdb9fff5b3fcf3b8fdfaaae4e8 +c4f4fec5f1feb5e1eeafe1eaa3d4d9d4fdffd5f0f7e5eef777767ec9c7cc4745465f5e5c +e8e7e3f3f3ebeaeae0e9e7dbf4f2e5efecddefecddefecdbefecddf1ebddf1ebddf1ebdf +f1ebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecdfeaecdef1ede2fde5e5f9e3e5f1edeee5eaede9edf6 +9797a3fffaffe5f3fc00251a0e7a635bd8ba1f7c6700090cffe9e7ffecc4ffffc446510f +ecffc4e7ffcfe3ffd6e4ffe1ddffdc000600f8f7f5fff4fe0d0004fff9fff5eceffffffa +fbfff9f1f3f0ffffff000000000000fffffff9f9f9fffffffcfcfcffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcfffdf7fff8e4f5ed757f8b +fef9ff896bb5170043320e5417014912116e0b147b060f7800026b0000560b0649f5ffff +425247f3f8f4fffffffffffffffffff5f5f5ffffffffffffffffffecececfffffff0f0f0 +fffffff1f1f1fffffffffffffffffff4f4f4fffffffffffff0f0f0fefefef1f1f1ffffff +fffffffffffffffffffbfbfbf5f5f5fffffff0f0f0f8f8f8fffffff9f9f9fdfdfdffffff +efefefffffff000000fffffffffffffdfdfdfffffffffffffafafafffffff2f2f2ffffff +ebebebfdfdfdfffffff2f2f2f6f6f6fcfcfcfafafafffffffffffff6f6f6ffffffffffff +fbfbfbfdfdfdfffffffafafafffffffbfbfbfffffffffffffffffff1f1f1ffffffffffff +fffffffffffffdfdfdf3f3f3fffffff4f4f4f2f2f2ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001dc80334d71c60f31e57bedee7fff4ebe2edf0dfeaefdb +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0 +eeebe6ece9e4f0ece1f0ebe7ece9f47b7a88dce5eae1f2fcd6ecffd0ecffceeeffc7e8fb +bdd8f5a3bbd591a7b5a0b7bd8eadafc0eae8baf3edabece6b0f2eeb6f4f3c8f9feb3dbe5 +afd5e0c0e6f1a7d4dac1f1f5e3ffffeaffffb2bcc88f8f99c1c1c32c2b2794938fe4e3de +e5e5dde5e5dbf0eee2f5f3e6efecddefecddefecddefecddf1ebdff1ebdff1eae0f1ebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecdfe9eddcf0eedffbe6e1fbe3e3f5ebece8e9ebe3f1f18b9d9f +f5fffff2ffff000b0700190d002110001202000900f7fff4f7ffdff0ffd4e3ffd43a7d36 +166820237835135d28043e18001200f8fffffff9ff0a0007fff9fffffbfffffefff7f9f6 +ffffffffffffececec1c1c1cfffffffdfdfdfdfdfdf6f6f6ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffefffffcfffff3fcfb8d989cfcfeff +8c798ffff4fffff6ecffeae4ecedffeeffffe2f9ffebffffe9ecff000023edf7ff586261 +fcfffff5f5f5f2f2f2ffffff000000000000000000050505fffffffafafa000000010101 +060606ffffffeaeaeaf9f9f9010101000000000000ffffffffffffffffff000000000000 +000000f0f0f0ffffff040404060606050505fffffffefefeffffff000000050505060606 +fbfbfb0404040202020000000b0b0beaeaeafefefeffffff000000131313000000ffffff +ffffffe4e4e4ffffffffffffffffff000000fffffff6f6f6ffffff000000ffffff000000 +090909000000ffffff000000000000f4f4f4fffffff8f8f8000000030303000000fefefe +e5e5e5030303070707000000020202fffffffafafafafafaffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001dc80334d71c60f31e57bedee7fff4ebe2edf0dfeaefdbeeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0efeae6 +efe8e2f2ece0f1ece6ede7f3777684d8e1e6dff0facbe1ffc9e5ffc7e7ffc4e7fbc2dffd +bad4ef899eafb1c5ce869da5b4d1d7d3ffffb8ebecb4e7eab1e1e5bbdde6c7e2edcbe2f0 +c0dbe6c6e8f1e1ffffdeffffd3e9f4707787bdbbc8757374474641dfded9f5f5ede7e7dd +ecece0f6f4e7e3e1d4efecddefecddefecddefebdff1eae0f1eae0f1eae0f1eae0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddeeebdaf4edddf6eadef2e8dff1eee9e5ece5e0f3ed89a09aedffff +f4ffff020c0b000300f3fffb001003001201dbffe6dcffda2a702a1d742f41a6624cbd7d +2091590b6e42166546001002f0fffffefeff120612180b150700040d080cfbfbfdfcfcfc +f5f5f5ffffff000000fafafaffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffefff9f5f6ffffff768185fbffff978486 +ffecddf8d1a64b2d0bfffcffe5f4ff001d2ce9ffffc7d5e20f1722f8ffff3b4345fafbfd +fffffffefefe020202f5f5f5fffffffafafa000000f3f3f30b0b0bf8f8f8fffffffafafa +000000ffffff000000fffffffffffff8f8f81f1f1fefefef000000fffffff7f7f7ffffff +fffffffafafafffffffcfcfce2e2e2040404f8f8f8000000fffffffafafafdfdfdffffff +000000f6f6f6fbfbfbebebeb0e0e0effffff000000f5f5f5f9f9f9f9f9f9000000ffffff +fbfbfbfffffff7f7f7ffffffffffff000000fdfdfd000000fdfdfdf5f5f50d0d0dfdfdfd +f5f5f5080808fbfbfbf2f2f2222222fafafaf3f3f3fffffffffffff1f1f1090909ffffff +070707f9f9f9f3f3f3ffffff000000f3f3f3ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001dc80334d71c60f31e57bedee7fff4ebe2edf0dfeaefdbeeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0f1eae4f0e7e2 +f3ebe0f4ede5ede5f0757381d4dde2ddeef8e0f6ffdaf6ffcff1ffc6e9fdc4e1ffb7d2ed +8fa6b68c9ca99fa4b76f7689b4cad7d0eef8d2f0fae3fbffdce8f8a8abbcd8d9edf2f9ff +f1ffffe1f7ffd2e6f1636f7db5b2c5afa7b62b27287e7d78e8e8e0f0f0e6eaeae0eeeee2 +f8f6e9e5e3d4efecddefecddefebdfefebdff1eae0f1eae2f1eae2f1eae2efebe0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff3e9ddfbe5d8fbeadaecefdae3f0dce4f5e3dfefe2e3f3e98d9e94f4fffdf0f9f4 +0e0202fff6f8190401f6f2e7001d05d0ffdd1e752483ed914ec778119655008858007554 +007966003c34001310e7fffff6fffffcf6faf9eef2fffbfffef9ff09070cf1f1f3ffffff +f9f9f9000000fffffff2f2f2fcfcfcffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffefdfffbfbfdf7f97f8792fbffff98848dfff0eb +511e03663a31fff4ff101555a2c0dc06292dd1e6dd030f01f0f7f0515652f9fbfaffffff +f7f7f7000000fffffffffffff4f4f40a0a0affffff000000060606070707000000000000 +ffffff101010fffffffbfbfbffffff000000ffffff000000fffffff5f5f5f7f7f7f3f3f3 +ffffff010101040404060606111111fcfcfc040404fffffffffffff2f2f2ffffff0b0b0b +fdfdfdffffffffffff0d0d0df2f2f2000000090909090909000000070707e6e6e6ffffff +f8f8f8fffffff7f7f7fafafafdfdfd060606ffffffffffffffffff030303f1f1f1f9f9f9 +131313f7f7f7fefefe000000f8f8f8ffffff080808000000141414000000fcfcfc080808 +f5f5f5ffffffffffff000000fffffff9f9f9ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001dc80334d71c60f31e57bedee7fff4ebe2edf0dfeaefdbeeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0f2ebe5efe8e2f3ece4 +f2ede9ece6f2727181d4dbe5dfecfdd3e3ffcde3ffcae3ffc7e2fdd2e9ffcadffec7d9ef +919cae908ea4b9b5cc6f7688828f9fdfedfad4ddecdcdbed918d9eb5adc2efecfde4ebfb +bdc9d5636c7ba8aebebdb5ca413948635f5eebebe3eeeee4edede1ecece0e3e4d6eeecdf +f1efe0efecddefecddefebdfefebdfefebe0efebe2f1eae2efebe2efebe0efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f5e8dffee3dcfee8ddebf0dadff3d8e1f7e0dcf1dee5f2e8909d94f5fffbfcfef90b0000 +250b0effeff4060000000904246a4888f5a643c86b008e42007d4600452959f3eb48cfd5 +6ed6e1001217defcfcfbfffdfffefafffdfdfcf8f9ffffff000002fffffff0f0f0fcfcfc +090909efefeffffffff8f8f8ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffefdfff5f1fffdfb7f838cf7f9ff8e7e88fff5f6fff1e1 +471f20ffeefff7f8ff3f556c375450dff0de020b00fefff650514cfffffdf6f6f6ffffff +090909f9f9f9f8f8f8ffffff000000f3f3f30e0e0effffffeeeeeefffffffffffff5f5f5 +000000fbfbfbfffffffbfbfb000000ffffff000000f8f8f8ffffffffffffffffff000000 +fffffff7f7f7ffffff000000f8f8f8000000fffffff9f9f9ffffffffffff000000fafafa +f9f9f9f8f8f8040404ffffff000000fffffff1f1f1fefefefefefefffffffafafafcfcfc +fffffffafafaffffffffffff000000fffffff4f4f4ffffff000000ffffffffffff000000 +ffffffffffff020202ffffff020202f4f4f4fffffffbfbfb000000f8f8f8000000ffffff +fffffffcfcfc030303fefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0ece9e2f5f4f0e2e1dfe9e7ec +f2f0fd605e739e9eb6babedbaeb2d8abb2dcaab3daaab4d8aab3daaab4d8abb4d5aeb3d0 +aeafc47978889597a69093a26b6e7d757887aaa9b983818f8380919998a66062718b8f9b +c4c7d69799a843405158555e7e7b76dddbcff6f4e8e2e0d3f3f1e4f5f3e6e4e2d5f0eee1 +eeecdfeeecdfeeecdfeeecdfeeecdfeeece0efebe0efebe0efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff3e9e0 +fbe2e5fce7e6f0eddce7efd7e6f6dcdff1dbe5f2e8919c98fbfffff7f9f8030000120d11 +00000c050f2a00072f002736098151008e47007f4500512d37ddd944e7f853e0fe003550 +000f19f5fffcfef5ec0f0500f3f3f1f9fffff8fffb000400fafcf9fffffffefefe000000 +fafafafffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff6fefbf27c7c7affffff857f83ede1e3f0e1dceddfde +e8e0ebe7e7f1e5eeebedf7ecd2d8ca0a0c00fffffa4a4a48fffffff1f1f1fefefe000000 +fffffff4f4f4fdfdfd020202ffffff000000fffffffbfbfbffffff000000f4f4f40e0e0e +ffffffffffffededed0e0e0effffff000000fffffffafafafdfdfdf9f9f90e0e0ef7f7f7 +f7f7f7ffffff000000ffffff040404fffffff0f0f0fffffff5f5f5000000fffffff0f0f0 +ffffff020202fefefe000000fffffffbfbfbffffff000000fffffff0f0f0101010ffffff +f8f8f8ffffff000000ffffff000000ffffffffffff000000f9f9f9ffffff000000ffffff +fdfdfd040404ffffff000000fffffffffffffafafa000000f5f5f50c0c0cfbfbfbfbfbfb +fdfdfd000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc7 +0738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeece0ebebe1f0f1ebe8e8e6eeedf2eceaf5 +89889a69677f646382747395737399737399717399717399707497717497717590787a89 +7e7e886b6b756c6c76a4a4aeb0b0baaeaeb8bebec8bebec8adadb7c7c7d1b1b1bb5b5b65 +38384276768078777cd7d7cffcfaedf1efe2dedccff0eee1f3f1e4e8e6d9f3f1e4eeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff2e9e2f8e4e6 +fae8e8f3ebdeeaeed7e8f5dbe1f0dbe5f2e9929b9afcfffffafafcfffffdecf0f3f7ffff +000123001049cfffff4ad5c200885a00926e3ceacf32edda008d7f009c910e837b00120a +f8fffbfffcf5fffdf400020000040001090bf9fefffeffffe3e3e30707070000000a0a0a +ffffffe8e8e8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffdf6f5f0fffffa999896f1eff216141908060b0100020b0a08080702 +08080001010001010015140f080705f2f0f5626065ffffffffffffffffffffffff000000 +0f0f0f000000010101f2f2f2ffffff000000000000080808ffffffffffffffffff000000 +0b0b0b000000fffffffafafaffffff000000070707000000ffffffeeeeee070707101010 +000000000000fefefeeeeeee0c0c0c000000000000ffffff020202eeeeeefffffffbfbfb +000000fdfdfdffffff000000000000000000ffffffffffffffffff000000f2f2f2ffffff +000000f6f6f6ffffffffffff000000f6f6f6040404ffffffffffff000000f6f6f6ffffff +030303fdfdfdf3f3f3090909000000010101141414ffffff0000001515150404040b0b0b +fbfbfbfefefefafafaffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc70738db +1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecdfeeefe1edede1ebebe3eaebe6e4e4e6d6d6e0 +87869682809573718971718d71718d70718d70728b6e738970728970738466666e6c6b70 +68676c68676c5b5a5f6261666b6a6f77767b87868b5352574e4d522f2e3352515679787d +e8e7ece2e2e2f8f8eef6f4e7eae8dbeae8dbf6f4e7f2f0e3e9e7daefede0eeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff2e9e0f5e5e5f7e9e6 +f0eddceaeed7e8f5dbe1f0dde6f1eb94999cfefdfffffefffffefbf6f6f4eff3fc020c25 +cad8ff6eafd73de4ea29fff517e4df2fffe500a75c00b74d0bd15a33c765001f00d0ebe2 +fefffffffefff9fff5fbfffffaf3fffff8fff9f6fffffffffefefefffffff1f1f1fcfcfc +fffffff3f3f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffefffffeff7a7885fffdfff6f4fffffdfff8f7fffffffff4f4f2fefffa +fffffbfffffffffefffffdfffffcff454253edecf2fffffff7f7f7f1f1f1fcfcfcefefef +ffffff000000fffffffffffff7f7f7fffffffffffff6f6f6fbfbfbf1f1f1fffffff7f7f7 +fffffffcfcfcfafafafcfcfcefefefffffffffffffedededfffffffdfdfdf8f8f8ffffff +fffffff7f7f7fffffffdfdfdfffffff1f1f1f9f9f9fffffff4f4f4f8f8f8f8f8f8ffffff +f2f2f2e8e8e8fffffffcfcfcfffffffffffff2f2f2fffffffffffffffffffefefef6f6f6 +fffffffffffffbfbfbfffffffbfbfbfffffff2f2f2f2f2f2fffffffffffffffffffcfcfc +fffffffffffffbfbfbffffffffffffedededfafafa000000fefefeffffffe1e1e1ffffff +fafafaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc70738db1c60f3 +1c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddeeeddbedeedceeefe1e9e9dfe3e2deffffffd5d4da +e5e5efeceaf8ebeafaebeafce9ebfae9ebf8e9ebf7e9ebf7e9ecf3f9f9f9e2e3def4f3ef +e7e8e37877736f706b87868274757064635f7879747a7975787974efeeeaeaebe6f5f4f0 +e8e7e2e8e5dce3e1d4ebe9dcf7f5e8f4f2e5eceaddebe9dceeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1eae0f2e7e3f4ebe4efeeda +e9efd5e8f4dce2efdee7f0ed95989dfffefffcf8f9fffff6fffff8feffff00000ec4cdee +33688a006c7d3ce7ee3ddfe200836a00a5571ece5f4beb6d44bd54001800f1fffbfeffff +fefcfffbfffbf5fbfbfaf4fff8effffffdfffffffff2f2f2fffffffffffff5f5f5ffffff +edededffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffefff0f0fc878592dddceac3c1cfc6c6d0d5d4dac2c4c3dfe0dbcccfc8c9cac5 +d0d2d1c7c6cedbdae8bcb8cf5b586bfffefffdfdfdffffffffffff030303020202000000 +fffffffafafafffffff7f7f7fbfbfbfbfbfbfffffffffffffffffffcfcfcfffffff1f1f1 +f9f9f9fffffffafafafffffff0f0f0fafafafdfdfdfffffffffffff5f5f5fffffff5f5f5 +fffffffffffff2f2f2fdfdfdfffffffdfdfdfffffffffffffffffff6f6f6f7f7f7ffffff +fffffff0f0f0fffffff6f6f6f7f7f7fffffffffffff2f2f2f6f6f6ffffffffffffe4e4e4 +fffffffffffffefefefffffffffffffffffff4f4f4fffffff6f6f6fefefef5f5f5ffffff +fafafafefefefffffffefefeffffffffffff020202fffffffffffffffffffffffff5f5f5 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc70738db1c60f31c55bc +e0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefecddecead5f0f0d8f2f1ddf1efe0edebdff7f7efe9e8e4f3f3f3 +eae8ebe9e8ede9e8ede8e9ede8e9ebe8eae9e8eae9e9eae5e5e5ddefefe5eeebe2f4f4ea +dedbd2e6e6dce6e3daefefe5eeebe2f6f6ecece9e0dbdbd1faf7eedfdfd5edeae1f1efe3 +f0eee2ebe9ddf1efe3f1efe3e6e4d8e8e6daf3f1e5f1efe3eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1e8e1f3ede1edefd9e7f0d5 +e8f4dee2eee0e7f0ef95989ffffdfffffefdefebdfffffeffffff40002000c1524000319 +00122200161b000d02000f00001c00001500001300001400000800fffff3fff7f4f0eeef +f8ffffeffefbf9fff8fcfff6f4f6f1fffffffefefefafafafffffff0f0f0ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fafcfbf9fdfe5a5b5f43474a595a5e5357564f514c545a504d5143464d3b4e5243595f53 +4a4c49494d50585864545460fcfbffecececfffffff8f8f8f9f9f9fffffffafafaffffff +ffffffeaeaeafffffffffffff0f0f0f2f2f2fcfcfcfbfbfbfffffffffffffafafaffffff +fefefeffffffeaeaeafffffffffffff1f1f1fffffffffffffffffff7f7f7f5f5f5ffffff +fdfdfdfffffffdfdfdffffffebebebf9f9f9fffffffafafafffffff4f4f4fafafaffffff +eeeeeefffffffffffffffffff6f6f6fdfdfdfffffffffffffffffffffffffffffffafafa +fcfcfcf3f3f3ffffffffffffe6e6e6fffffffffffffffffffdfdfdfffffffffffff0f0f0 +fffffffffffff2f2f2fffffffffffff8f8f8f1f1f1fffffff7f7f7f8f8f8fffffff8f8f8 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc70738db1c60f31c55bce0e9ff +f4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecdbf2f0d9edebd2e9e9d1f0efdbf3f1e2e8e6d9eae7dee4e4dcf1eee9 +efeeeaefeee9eeefe9efefe7eef0e5efefe5efefe3e7e5d8faf8e9e6e2d6e5e3d4fbf7eb +faf8e9e6e2d6f7f5e6f3efe3efeddee2ded2edebdcf7f3e7e9e7d8ede9ddebe9dcf4f2e6 +eeece0eeece0eceadeeae8dcf3f1e5f5f3e7e9e7dbeeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff0eadef1eedfedefd9e9eed7eaf3e0 +e3ede4e7eff29498a1fdfefffdfef9ffffedfeffe8fbffeaf2ffedeffefbf1fffff3fbf0 +feffedf9f3d9ffffecfffefffefdffebebfffffcfffff4f0fffdedf0eadafffff6f6ffff +f5ffffeefae4f2fae3fefffafbfbfbfafafafffffff6f6f6fffffff5f5f5ecececffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffdf9fef7 +fcfffaf8fdf9fcfffff0f4f5f4f8f7fcfffdedf2ebfcfff6fcfff3fcfff3fcfff4fafff8 +edf2eefcfffffbfffffefffffffffffcfcfcfbfbfbfffffffffffffcfcfcf9f9f9ffffff +fffffffffffff2f2f2fffffffffffffefefef8f8f8eeeeeefffffffffffff7f7f7fdfdfd +fffffffbfbfbfffffff6f6f6fffffffffffff7f7f7efefefffffffffffffffffffffffff +fbfbfbfffffffcfcfcf4f4f4fffffffffffff9f9f9fffffffffffffffffffffffff1f1f1 +fffffff3f3f3fbfbfbfffffff4f4f4ffffffffffffefefeffefefeffffffffffffffffff +fbfbfbf8f8f8fbfbfbfffffff8f8f8fffffffefefefbfbfbfbfbfbf1f1f1ffffffffffff +e5e5e5fffffffcfcfcf7f7f7fafafafffffffefefefffffffffffff2f2f2ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001cc70738db1c60f31c55bce0e9fff4ebe2 +e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecdbf6f4ddeae8cfe8e6cff0eddaedead9f1eedff1ede1f2f0e4ede9e0ece9e0 +eceadeeaebddeceaddeaebdbecebd9ecebd9f4f1e0f2efdef9f3e5f1eeddf4eee0ebe8d7 +f1ebddedead9e8e2d4f8f5e4eee8daefecdbfffbededead9efe9dbf9f6e7e9e7dae9e7db +ebe9ddefede1f4f2e6f4f2e6eeece0e9e7dbeeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff0eadcf1eeddedefd7eaeed7ebf2e2e5ece5 +e7eef49299a3f1f9fc4b574d79886b33481f758c62839d787692797e9f80739f64335d1e +809b6e808f7c686f818d8fb5f9fafff9f8fffffffff6f8e3feffe4fcffe8f8fff0f1f6ef +fffff8fffefafffffdfafafafffffffffffffcfcfcfdfdfdfffffffefefeffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffbfcfff6f4fced +edf4edf7fdfdfbfffffbfffff6fafffbfffffbfffff7fdfbf3faf3f9fff8fbfffafbfffb +fbfffdf0f4f3edefeefffffffcfcfcf8f8f8fffffffffffff2f2f2fffffff6f6f6ffffff +f2f2f2ffffffffffffffffffefefeffffffffffffffffffff0f0f0fefefeffffffececec +fffffffbfbfbfffffff8f8f8fffffffafafafffffff9f9f9fefefeebebebfffffff7f7f7 +fcfcfcfffffffcfcfcfffffff1f1f1fdfdfdf7f7f7f5f5f5f2f2f2f3f3f3fffffff8f8f8 +fffffffefefefbfbfbfffffffffffff6f6f6fffffff8f8f8ffffffecececedededffffff +fffffff8f8f8fffffffefefef8f8f8fdfdfdfffffff8f8f8ffffffffffffecececffffff +fbfbfbfffffffdfdfdfffffff9f9f9fffffff3f3f3fdfdfdfffffff9f9f9ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001cc70738db1c60f31c55bce0e9fff4ebe2e8ebda +ebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecddf1efdaeae8d3f6f3e0faf7e4e2dfcef8f5e6e6e2d6f4f0e5f0ece1f0ece1f0ece0 +efeddef0eddeefeedcf0eddaf0eddaf2ecdcede7d9f4eee0e9e3d5faf4e6efe9dbf5efe1 +efe9dbf6f0e2f2ecdef2ecdeede7d9f4eee0e9e3d5fbf5e7e8e2d4f1ede2f1efe3efede1 +f0eee2efede1e5e3d7e7e5d9faf8eceeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddf0eadcf3eedbf0eed7ebedd7eef0e2e6ebe5e7eef6 +909aa4f4ffff7e9487405e38769b674269305e8953e6ffe65d8f5c2c681e6ca55e355e34 +e8fff3f5ffff8182a100001cfefcfff9fdfffbfff4eaf7dbf7ffe2feffedfffcf3fffaff +fff9fff6f1f5ffffffeeeeeefffffffefefefffffffbfbfbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefffbf2f8ee8b93887b8181 +8a8e998082978182a078789a8687a68485a17f8196858897878b94777c808186897d8383 +85898a888a89f9f9f9fefefefffffff7f7f7fffffffffffffbfbfbffffffffffffffffff +fafafafefefef9f9f9fffffff1f1f1fafafaf4f4f4fffffffffffff6f6f6ffffffffffff +fafafaf8f8f8fffffff4f4f4fffffffafafafffffff8f8f8fffffffffffffbfbfbffffff +f0f0f0fffffff2f2f2fffffffffffffffffffffffffffffffffffff9f9f9fffffff7f7f7 +fffffffcfcfcfafafafbfbfbffffffefefeffffffffbfbfbfffffffffffff7f7f7f4f4f4 +fffffffdfdfdf2f2f2fffffffffffffffffffffffff3f3f3ffffffffffffe8e8e8ffffff +f6f6f6fffffffffffff7f7f7fcfcfcffffffffffffedededffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9 +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdffefaeee4e0d4f5f1e5f0ece0050100f6f2e6f0ece0eeebdc +f0eddceeebda040100f0eddeeeeadeebe7dcfbf7ece6e2d7eee7ddf5eee4efe9dde8e5d6 +fcf6e8040100070100060000090300070000fbf3e8dfd7ccf7efe4eee6dbeee6dbf5ede2 +f7efe4eae2d7e5ddd2faf2e7f1e9dee9e1d6fbf3e8ebe4daf8f4e9e2dfd6ece9e0f4f1e8 +e4e1d8f0ede4f2efe6e8e5dcebe8dfefece3eeebe2f0ede4edeae1e9e6ddece9e0edebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1ebddf1e9dcf4eddbf2edd7eeecd7eff0e2e8eae5e6eff68d9ba4 +eeffff375a46e2ffe22a60226aa6602966215f9c6335713b5c965b396a3b668677f2ffff +fcffff7d7978fffef8060100feffffdee3e6f9fffbfafff2fdfeecfffdf8fff7fffff7ff +f2edf4fffffffefefef6f6f6fffffffefefef3f3f3ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffefffffcffff7e8387bcbfd0c1c2e1 +cccafbbebaf7cec9ffbcb6fcbfbafcc4c1fab8b6e5c7c7ebc9cbe4b7bacdcdd0df7b7e87 +000004f4f4f4fffffffffffffafafafefefefffffffefefefffffff6f6f6ffffffffffff +f8f8f8fdfdfdfffffff6f6f6ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfece8dcede9ddfbf7ebf4f0e4040000ede9ddeae6daefebdfeeeade +e9e5d9110d02e5e1d6efebe2f8f4ebe8e4dbf9f5ecfbf4ecf7f0e6e8e1d7ede7dbede7db +060000fdf7e9ece6dae9e0d7f4ebe40e0500f4ebe4ece3dcfffdf6ebe2dbf1e8e1e8dfd8 +fff6effff7f0e1d8d1f2e9e2fffcf5e2d9d2fbf4ece8e4dbfdfaf1faf7eee5e2d9fcf9f0 +f0ede4edeae1f2efe6f5f2e9e1ded5f1eee5e7e4dbf7f4eb100d04edeae1edebdfefebe0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff1ebdff1e9dcf5ecdbf3edd7f0ebd7f1efe2e8eae5e6eff68a9da3eaffff +dffff2326d37d8ffd417601167b166236b2b539660346c3d76a382e4fffaeefffdf8fef2 +060000100700070000000004fbfffffbfffffefffffffdfafcedf0fff8fffdeefffffdff +fdfdfdfffffffffffffffffff6f6f6fffffffbfbfbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffefffff7fbfc91959ecfd1e80a093106033c +08024a090252130b5e0d0653201b5e0c09400000270e0e301719320b0e217f818d000004 +ffffffffffffffffffffffffffffffe6e6e6fffffffffffffcfcfcf9f9f9ffffffffffff +fefefefafafaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff3efe3f8f4e8e4e0d4f1ede10f0b000b0700f3efe3e7e3d8eeebe2090600 +030000eae7e0f1eee7eeebe4f3eee8f0ebe5eae5dfdfdbd2f6efe7fdf6ecf2ebe1060000 +f8f1e7efe8e0f8f1ebe3dcd6060000f0e9e3f4ede7e5ded8f2ebe5faf3edfaf3edece5df +ebe4deece5dffbf4eee8e1dbfef7f1e5ded8eae6ddf4f1e8dbd8cff9f6edf2efe6e9e6dd +e4e1d8ebe8dfe8e5dcfffef5eeebe2ebe8dfedeae1030000f0ede4fdfbefefebe0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff1ebdff1e9def4edddf4ecd9f1ead8f2eee2e9eae5e6eff48a9da1e4ffffdbfff0 +d8ffe1145d14d1ffcf1e6c205fab6a286c395d9572dcffefdfffeae9ffecf7fff1fffff6 +fef4f5c4bac205080dedf4fcfafcfff4f0fffff8fffff2fffef2f6fffefbfbfaf8ffffff +f2f2f2fcfcfcfcfcfcfffffff5f5f5fdfdfdffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffefffffcfffd797d80b5b7c60e0d2d130f410a0442 +120b4f120b510d0649e4dfff0b0835fcfbff05051ff9faff00000c999ca3010204fbfbfb +f5f5f5edededfffffffffffffefefef5f5f5fffffffffffffcfcfcf6f6f6fcfcfcffffff +ffffffedededffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfe8e4d8e4e0d4f5f1e5f2eee2040000040000f1ede1fffff3e5e5dd12110c010000 +eae9e4f3f0eb030000f3f0e9e1dcd6050000ede8e2f4ede5f4ede5ded7cf0d0600e1dad2 +f2ebe5f2ebe5f3ebe81d1512e2dad7f6eeebf9f1ee060000060000060000ece4e1fff7f4 +faf2ef080000070000110906eae5dfeeebe4f5f2e9060300060300030000efece3eae7de +100d04e6e3da110e05030000e5e2d9fefbf2030000120f06d5d2c9efebe0efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeeadef3eddff3ecdaf1ead8f4eee2eae9e5e7eef48a9da1e7ffffdffff31c5d25 +69b269237022c4ffc6297034589768285939749f813f7043deffddedffe9fffffafffaff +d6cad6000004fbfffffefefff9f0fffff6ff150216030000fbfcf4fffffdf7f7f7ffffff +0a0a0afafafaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffdfefffa828781cacbd07f80928683a28e8cb17a759e +78769e8682a781809f8a889e8c8e9d81818d7c7f86a3a4a96e6f730c0c0ef6f6f6ffffff +fffffffffffff6f6f6fffffffffffff0f0f0fffffffcfcfcfffffffefefefffffff7f7f7 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f5f1e5f6f2e6f8f4e8ede9dd151105f5f1e5040000e1dfd3080a00d5d6ce040500f2f3eb +efefe7010100fbfbf3f4f1e8030000f5f2e9f6f2e9f0ece3fdf6f00700000e0701060000 +040000050000dcd7d1f3eee8eee9e3040000fffaf4e9e4deeae5df130e08e4dfd9040000 +f9f4eee3ded8efeae4110c06eeebe4030000ebe8e1f0ede6f1eee7050200fffff8030000 +080500e0ddd6eae7e0060300faf7f0030000e7e4ddfffff6efebe0efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdf +ebebdfeeefe1f2eddaf0ebd8f5ede2ece9e4eaedf28d9c9fdafaef487659629d672c6f2a +5a9c55317230dcffe338683e7897753654325f8764eaffefeaf8ebf8f4f3fff9ffd2c1c7 +060500fbfef5fffffafffcfd0d0005fff9fff8fbfff7fffff1f5f6fefefe060606000000 +f5f5f5fffffff6f6f6ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff674786ae0e1d9ebede8fcfcfcfefffff6f6f4fefffa +fffff6fdfff2fffff3edf1e2fffff6fefffaf5f5f3828282000000fffffffcfcfcfafafa +f6f6f6fffffffbfbfbffffffffffffffffffffffffe9e9e9fffffff2f2f2fffffffdfdfd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc8 +0030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfe3dfd3 +f3efe3f0ece0d5d1c5040000f7f3e7060200f8f6ea000200fafdf2000200eaece1cfd1c6 +0f1106e2e2d8e9e9dd030000fffcf3cdc9c0e8e4dbfdf6f0060000efe8e2f6f1ebe2ddd7 +f7f3ea100b05faf6ede7e2dc050100040000040000080300090500f4efe9040000fdf8f2 +eae6ddece7e1ddd8d2f0ede60b0801030000060300030000030000ebe8e10a0700f4f1ea +ebe8e1f9f6ef030000e1ded7030000efece5eae7deefebe0efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0e9ece1 +ecf0e2efeedcf0ebd8f5ede2ede8e2ecedf1909b9dedfffd4c7459366b37639e5e275e1d +6b9e652c562ee4ffe439562882a27336643dd3fee2f1fffbfcfffffbf0f6cfc3c7000100 +fbfef5fbf7ee080000fff9fbfffbfff1fcfff2fffff7fdfdffffffffffff000000ffffff +edededfffffff3f3f3ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffdfffffa7a7b73c6c8bdfffff3ffffefeff3daffffe360673e6f7748 +000800fbffd8ffffe3feffecfffff6fcfcfe8a898f070709fffffffefefeffffff000000 +000000000000000000f0f0f0f1f1f10b0b0b020202050505fffffff6f6f6ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d3 +2064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdffefaeedfdbcf +fefaeefefaee0e0a00e2ded2f0ece0030100e8ecdee2e8da000400eef2e4fbfff1070b00 +d8dacdfbfdef060600dbdbcffffff4f3f1e5e4e0d7040000fffbf5e4dfd9fcf8efe4e2d6 +030000e6e4d8fbf8ef171509dedbd2faf8ecf3f0e7e1dfd3f9f6ed030100f5f2e9f6f4e8 +e2dfd6fffff6e7e4dd030000f2efe8e4e1daefece5fffff8e4e1da090600edeae3e4e1da +f6f3ec0c0902e9e6df080500f4f1eae5e2d9efebe0efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfecece0e6eee3e9f1e4 +ecefdeeeebdaf5ede0efe8e2eeecef929a9ce9fef53c5e45749f7136662c6f9a62365a2c +8fa98c3c5736ebffd42457145a9e652c6d43e3fffaeafffbf0f3facecdd5000205fbffff +fffefb0b0000110000070000000700eefff8f9fffdf0f0f0f6f6f6000000f4f4f4ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffff1eef798959ec6c4c5fefef4f4f6e0ffffdffcffcf101800e7f0ad798241 +030a00fdffdaffffefe3e1e2fffcff858094000005fffffff5f5f5000000f8f8f8ffffff +ffffff020202ffffff000000fffffff8f8f8fbfbfb000000fffffff2f2f2ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f7 +1851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfe5e1d5f8f4e8ece8dc +e8e4d8060200e8e4d8faf6ea030100e8eaddf0f4e6010500e3e7d9e9ebddf4f6e8000200 +010200ebecdef3f4e6d9d7cbefede1f8f4eb040000e5e1d8f3efe6e9e7dbf3f1e5090700 +f4f2e6e9e7db030100fefcf0e9e7dbeeece0030100efede1090700e3e1d5f0eee2f8f6ea +030100f2efe6090600e4e1daf1eee5e9e6df0b0800d9d6cf080500ece9e2faf7eeebe8e1 +030000f1eee70e0b02e0ddd6eeebe2efebe0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfecece0e9ece1eaf0e4ecefde +edebdcf4eee2efe8e2eeecef95999cf7fffff2fff6e6ffe2ebffde829872f4ffe7edf8e7 +7e90763c5f276b9e5c2968335f9973001200e6fdf7fbffffbebeca010510fcfffffaf6f7 +0a0000fffbf4fffceff8fff3000700fbfffbf6f6f6ffffff000000fbfbfbfffffff6f6f6 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff858587c8c8c8f8f7f2ffffedffffe36b6e43ebf0b889904d89904d010800 +767a55feffebfffffdfffcff868398040309f1f1f1ffffff060606f7f7f7f6f6f6ffffff +000000f8f8f8050505fefefeffffffffffff010101f5f5f5ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001ec90031d42165f81952b9 +e3ecfff0e7def0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdff7f5e8e7e5d8eeecdff1efe2 +030100f2f0e3fcfaede6e4d7edede1eaeade010100edede1f7f7ebdfdfd3010100f7f5e9 +e5e3d7f4f2e6eeece0dfddd1fbf9ed090700e6e4d8f3f1e5f0eee2e2e0d40d0b00f6f4e8 +e4e2d6eae8dc0a0800030100030100e7e5d9efede1efede1030100030100070500eeece0 +eceadeeeece0090600030100030000edebdfedeae1060400f1eee5eeece0e6e3da030100 +f0ede4f4f2e6040100eae8dcefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeadef1ede1f0ece0eeeadf +f2ede7ece8e5eeecef98979cfbfcfffefffffaf9f5fbf8f1878078fff9f3fffffafcfff4 +f4ffea000d00eeffefedfff0000800fcfefdfdf8fed5cdd806030cfcf9fffffdff060002 +fffbfdfffcfbfef9f6010000fffffdfafafaffffff000000fffffffcfcfcf9f9f9ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefff8 +feffec878f77c5c8bffffffdfffff8f8f5ecfffff6060100d0cf9feef1bc050700eff2d5 +ffffe8f9feeafcffff7b7e830c0c0eefefefffffff000000f3f3f3ffffffffffff000000 +f8f8f8050505fefefeffffffffffff010101f5f5f5ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001ec90031d42165f81952b9e3ecff +f0e7def0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfe4e2d5f5f3e6f5f3e6e3e1d4f9f7ea +dfddd0e6e4d7eeecdfe6e4d8fffef2eae8dce6e4d8eceadefffdf1030100ebe9ddf9f7eb +eeece0f5f3e7e5e3d7eae8dceeece0ebe9ddefede1e8e6dafffff4e9e7dbe8e6dafffef2 +dfddd1f6f4e8f0eee2f2f0e4fffef2edebdfeae8dcf7f5e9f5f3e7e1dfd3efede1f0eee2 +f1efe3e5e3d7fffff4eae8dce4e2d6fffef2e6e4d8e8e6daf1efe3eeece0f2f0e4eeece0 +e6e4d8e8e6daeeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff1ebddf1e9dcf4ecdff2ece0eeeae1f1eee9 +eae9e7ededef98979cfbfafffffefffaf5fbfffdff969094fffdfff9f3f3f7f8f3e5f1e5 +f7fff80003000a0c07030000fffdfffef8fcbcb6ba010004f7f6fbfeffff000004f5f5f7 +fcfafdfffdff030002fffeffffffffffffff080808ffffffefefefffffffeaeaeaffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefff8f6fee6 +7e866ecbcdc8e9e8edfffdfefffdfffff9fffffcfd060300040500ffffedfffff3ffffea +f0f5e1fcffff80838c000004f7f7f7ffffff000000fffffffdfdfdededed131313ffffff +000000fffffff8f8f8fbfbfb000000fffffff2f2f2ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001ec90031d42165f81952b9e3ecfff0e7de +f0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdff4f2e5efede0edebdef5f3e6f3f1e4eeecdf +fffff2efede0f4f2e6e4e2d6fbf9ededebdf030100050300dddbcff8f6eadddbcfe8e6da +f9f7ebf3f1e5e5e3d7f8f6eae7e5d9f1efe3e4e2d6eeece0e6e4d8f7f5e9e5e3d7f1efe3 +f9f7ebe4e2d6ebe9dde0ded2efede1eceadeebe9dde8e6daf7f5e9eceadeebe9dddbd9cd +f9f7ebeceadeeeece0e2e0d4efede1f3f1e5f0eee2efede1f6f4e8eceadeeeece0e5e3d7 +f1efe3f5f3e7efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefecddf0eadcf3eddff2ece0eeeae1efeee9e8eae7 +eaeeef95999cf5f8fdf9fffff2fffff0ffff607973f0fffdf8fefafefffffcffff000104 +fefffff2f0f30c0809fefafbf6f5f3d3d5d2000200f8fffdecfbf6f4ffff000603000505 +000405f8fffffcfffffbfbfb0000000000000b0b0bffffffeeeeeeffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffff8b8c90 +d0d0dcfefefffffefffffdfff0ebfff5f2fbffffe6feffe2fcfafbfffefff7faefeceee9 +fefcff7a77940f0d18fffffffffffff8f8f8090909000000020202000000f0f0f0f1f1f1 +0b0b0b020202050505fffffff6f6f6ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2 +e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeceaddebe9dceae8dbf2f0e3e6e4d7eeecdfe8e6d9 +e9e7dae3e1d5f2f0e4e5e3d7f8f6eaf4f2e6f8f6eaf6f4e8edebdfefede1f3f1e5e2e0d4 +f3f1e5fffef2d2d0c4f6f4e8e6e4d8fefcf0e3e1d5e7e5d9fdfbefedebdff1efe3eceade +eae8dcf4f2e6edebdfebe9ddfdfbefe1dfd3f3f1e5f1efe3eae8dcfffdf1f0eee2edebdf +e5e3d7e8e6dafbf9ede5e3d7eeece0e9e7dbefede1e8e6dae9e7dbfdfbefeeece0fefcf0 +e0ded2efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddf0eadaf3edddf2ece0edeae1eeefe9e6ebe7e9efef +929a9cf9fffff7ffffe5f9f8edffff75948cedfffff0fffaf6fcfcf9f7ff0802100c0612 +09020a050003fffefd010000ced1ca000400f7fffaecfdf3f2fffdf1fffff2fffff2ffff +f7fffff0f4f5fffffffffffffffffffcfcfcfffffffffffff7f7f7ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdff85848c7b7a8a +81808e7d7e82898a8e898b988d9095757e63828b707d7d85807f8d8385848f91906e6a81 +9692ab000007fffffffdfdfdfffffffefefef5f5f5fefefe000000ffffffffffffffffff +e9e9e9fffffff2f2f2fffffffdfdfdffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2e9eeda +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfe8e6d9fdfbeee6e4d7f6f4e7e8e6d9efede0fffdf0e6e4d7 +faf8eceeece0e5e3d7e9e7dbdddbcff0eee2f4f2e6dad8ccf3f1e5f5f3e7e9e7dbedebdf +e3e1d5fffff4eeece0ebe9dde2e0d4eceadefefcf0e3e1d5e2e0d4e8e6daedebdff7f5e9 +eceadeeae8dcf6f4e8e6e4d8f7f5e9e6e4d8f3f1e5f1efe3e1dfd3f5f3e7ebe9ddfefcf0 +efede1f3f1e5e1dfd3f2f0e4eeece0eae8dcf1efe3f6f4e8d6d4c8f8f6eae4e2d6ebe9dd +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1ebddf1eadaf3edddefede0eaecdfebf0e9e3ece7e6f0ef919b9c +e9f3f5f8fffff8fffff2fdff7b8787c0cfccbfd0cac2cccddfd9e7b6a7badaccdddcd0da +bdb2b8bfb7b5050000c4c4ba030500ebf1e5fbfffaeef7f2f9fffff9ffffe6edf5f9feff +feffffebebebfffffffffffffffffff4f4f4ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffafffff1010100000005111119 +00020000040000040000050000080007150001090b00000b06070c010100010000010000 +141412e5e5e5fffffff1f1f1101010010101000000fffffff0f0f0fffffffcfcfcffffff +fefefefffffff7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2e9eedaeeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdff7f5e8e9e7daf0eee10301000301000301000b0900efede0ebe9dd +e9e7dbfbf9ede2e0d4fffff4f3f1e5e0ded2fffff4dfddd1edebdff9f7ebf1efe3d5d3c7 +f7f5e9e0ded2f3f1e5e8e6dafffff3e6e4d8f6f4e8e9e7dbfffff4dcdacee3e1d5f1efe3 +eae8dce6e4d8d6d4c8fffff4f2f0e4eeece0e7e5d9e6e4d8fbf9ede5e3d7dedcd0eae8dc +f0eee2fbf9ede8e6daf8f6eae8e6daedebdfe8e6dafcfaeee5e3d7efede1fffef2efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff1ebddf2e9daf4edddedeedee7eddfeaf1e9e3ece7e6f0ef919b9df8ffff +f8fdfffff8fffffaff90838d0e090f000402000806030004180b14070002060000130e0b +06030018150e010100010100fffff8f9f8f3fbfaf8f4f2f5fefcfffffdfffffdffffffff +fafafaffffffffffffeeeeeefffffffbfbfbffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffff8ffffebfffeeaffffffebecf1f9fff8 +f7fff4f5fff8f0fff4f4fff6f2fff5f7fffff1f8fffefdfffffefffefcedffffedf6f5f0 +fffffffcfcfcf9f9f9fefefefdfdfdfffffffbfbfbfffffffffffffcfcfcf6f6f6fcfcfc +ffffffffffffedededffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2e9eedaeeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfe0ded1f4f2e5f1efe2030100fbf9ecf3f1e4eae8db060400e9e7dbf3f1e5 +edebdfefede1f0eee2dbd9cdf1efe3dddbcffaf8ececeadeebe9ddeeece0fefcf0ebe9dd +efede1e9e7dbf1efe3edebdfe2e0d4e9e7dbedebdfe8e6daeeece0fbf9ede8e6daf6f4e8 +f2f0e4f6f4e8e7e5d9ebe9dde6e4d8f5f3e7f0eee2ebe9ddedebdff6f4e8f7f5e9dfddd1 +ebe9ddf2f0e4e1dfd3161408f7f5e9dddbcff4f2e6f9f7ebe0ded2e5e3d7efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff1ebddf5e7daf5ecddebefdee4efdfe8f2e9e3ece7e7f0ef929a9deaeff5fffcff +fff2ffffe1f8ffefffffe1f0feffffe7f4ebfdfff2ffffefffffeffcffeffbfff4f7fff2 +e8ede6fdfffaf7f6f4fef8f8fff6f9fff9fdfffbfffff9fdf4e5eafffbfffefafbf0f0f0 +fffffff9f9f9ffffffffffffffffffefefefffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffafffff1fefcf0edecf2fcfffff8fff8e5f7e7 +f1fffdecfffff0ffffedfffff1fffff0f9fefcfcffe9e6fbfbf8efffffeff7f6f1ffffff +fbfbfbfffffffffffffffffff7f7f7fffffffffffffcfcfcf9f9f9fffffffffffffefefe +fafafaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2e9eedaeeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdff5f3e6f0eee1e8e6d9080600eeecdff0eee1e3e1d4f7f5e8060400eeece0e7e5d9 +eceadef5f3e7edebdffaf8ececeadef2f0e4e7e5d9f4f2e6e8e6dae8e6daf9f7ebe7e5d9 +f2f0e4eeece0f2f0e4edebdffbf9ede8e6dae9e7dbf5f3e7e6e4d8f2f0e4e6e4d8eeece0 +f0eee2ebe9ddedebdff5f3e7e9e7dbedebdfeeece0eeece0f0eee2e2e0d4faf8ecefede1 +e9e7dbf2f0e4030100dfddd1fdfbefe6e4d8edebdfebe9ddf5f3e7efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f1ebddf4e8daf5ecddedeedee6eedfeaf1e9e3ece7e7f0ef94999dfefefffff6fffff4ff +fff2ffffe3f817000b050308000400000700000800000c00000a00000800f5fff3eefef3 +f8fffffcfffff9f6fdfffbfff9eef6f9edf1fffbfbfffcf8fffbf8fffffdffffffffffff +fdfdfdfffffff9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff6fefaf7fffcfff8faffe6f1fff1ffffb5c5f9 +b5c4ffb3c0ffbecaffbac5fbf5fcfff2f1fffefbfffffdfff9f6effffffdf7f7f7ffffff +fffffff7f7f7fffffffefefefefefefffffff6f6f6fffffffffffff8f8f8fdfdfdffffff +f6f6f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +f4f2e5efede0e5e3d6080600e3e1d4fcfaeddedccfedebde030100fefcf0ebe9dde5e3d7 +030100040200030100eeece0f4f2e6edebdf030100131105030100eceadefaf8ec030100 +ebe9ddfaf8ece8e6da030100f3f1e5030100030100040200e9e7db0705000d0b00ebe9dd +dfddd1fffef2030100060400030100e7e5d9fbf9ed040200eae8dc050300030100efede1 +eeece00c0a00030100f1efe3f6f4e8040200030100f6f4e8efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdd +f0eadaf4edddf2ecdeedebdfebf0e9e3ece7e9eef197989dfffbfffffbfff7f9fff4fdff +f4ffff000305fffdfffffeeeeaeaaaffffb5e1efa4f2ffc9000d00000e00f0fffbe8fafa +f3fdfff9fffff5f5fffffefffbf9faf7f8f0fafeedfcfff3fdfffafefefeffffffffffff +ebebebfefefefdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffdfffffbfffefff0effff8f9ffbabcffabadff100eb90704c3 +0b09c20b08b702009fc7c2ffc5c4fffcfafffaf5fffffcfffcfbfffffffffffffff2f2f2 +fffffffcfcfcfffffff5f5f5fafafaf8f8f8fffffffffffff8f8f8fffffffffffff6f6f6 +fffffffdfdfdfffffffffffffbfbfbfffffff7f7f7fcfcfcfafafaf4f4f4ffffffffffff +f6f6f6fffffffffffffafafafbfbfbf6f6f6fffffffffffffafafaf5f5f5fffffff6f6f6 +f6f6f6fffffff5f5f5fafafafffffffffffff6f6f6fbfbfbf4f4f4fffffff8f8f8f7f7f7 +fffffffdfdfdfffffffbfbfbfffffffefefefffffffffffff7f7f7fbfbfbfffffffcfcfc +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc7 +0738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfe9e7da +dfddd0f3f1e4090700eae8dbf8f6e9fcfaede9e7da030100dddbcfedebdf0d0b00fdfbef +e5e3d7e7e5d90b0900e8e6da090700e8e6dae5e3d7fbf9ed030100edebdf030100e9e7db +faf8ecf1efe3060400dfddd1100e02f3f1e5f7f5e9090700f4f2e6e4e2d6050300f4f2e6 +050300e3e1d5e9e7dbf7f5e9030100dfddd10301000b0900e3e1d5f5f3e7030100f1efe3 +030100f1efe3e2e0d4040200f3f1e5e0ded2030100efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddebecda +f1eeddf7e9def4e7dfedf0e9e3ece7e9eef198979ffff9ffe8e8f4001614001d11001c09 +002215000007fff9ecffffb6e6dd78ffffb0f5fdb4000a00f1ffe6021309f2fffff5fcff +fbfefffffcfffffdfffefffdfcfff4f8ffedf4ffeaf9fcf5fffffff7f7f7fdfdfdffffff +fffffff6f6f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffdf8f9f4fcfefff9f8ffc7c3ff0e0c89201cb70000bb0f0cd90000cb +110dd40b04b41712a4160f7faba7f4fcf9fff1eefffcfbfffffffff7f7f7fffffff9f9f9 +fafafafcfcfcfffffffffffffffffffafafaf6f6f6ffffffecececfffffffffffff7f7f7 +ffffffe4e4e4fffffff6f6f6fffffff0f0f0fffffffffffffffffff0f0f0fefefeffffff +ecececfffffffbfbfbfcfcfcffffffeaeaeafffffffbfbfbfffffffbfbfbffffffffffff +fbfbfbfffffffbfbfbffffffeaeaeafffffffcfcfcfffffffffffff3f3f3ffffffffffff +f6f6f6fcfcfcffffffefefeffffffff1f1f1ffffffffffffffffffefefefffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc70738db +1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdff6f4e7f3f1e4 +eceadd030100dfddd0e6e4d7e1dfd2f8f6e9030100fffff4eae8dc030100eceadee8e6da +f3f1e5030100fffef2030100dedcd0fffff4eceaded7d5c9fffdf1090700fcfaeed2d0c4 +f9f7eb030100ebe9dd030100ebe9dde1dfd3030100dfddd1f7f5e9080600e6e4d8030100 +0301000e0c00030100030100f3f1e50a0800f1efe3eeece0e8e6da121004e5e3d718160a +e5e3d7e9e7dbf4f2e60c0a00fdfbefe5e3d7efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddde6f0d8eef0db +fee5defce3dfeeefe9e2ede7e7eff199969ff8e3f4f5ffff001f0c47ddb7009d6f4fcfae +00020972413a673300fffc98f3cf77fffeb8140a00fdf9def6f5f0080510fffafffff7ff +fff2fffff7fffffefdecf0e2f9ffedf9ffedfefffafefefefafafafffffff6f6f6eaeaea +fdfdfdf9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffefffbfbfff3f2f7ffbab6ff02008315129d050889edf5ffe2ebffebeeffedefff +eef7ff1115790900a411039ecdccfffafefff9fafefffffffbfbfbfffffff5f5f5ffffff +ffffffededede7e7e7fcfcfcfffffffffffffcfcfcfffffffcfcfcfffffffffffffefefe +fffffffffffffffffff6f6f6ffffffe9e9e9eeeeeefffffffffffff7f7f7fdfdfdffffff +fbfbfbfffffffffffff1f1f1fffffff7f7f7fefefefffffff8f8f8fbfbfbfbfbfbf8f8f8 +fffffffefefef7f7f7fffffff1f1f1fffffffbfbfbecececfffffffffffff9f9f9ffffff +f4f4f4f2f2f2fffffffffffffffffff7f7f7efefeffafafafffffff3f3f3ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc70738db1c60f3 +1c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfe1dfd2f7f5e8eae8db +040200fdfbeef3f1e4fffdf0d9d7ca0b0900e3e1d5e7e5d9100e02e9e7dbf8f6eaefede1 +0a0800dedcd0080600f5f3e7ebe9ddedebdff6f4e8ebe9dd030100dcdacefefcf0e4e2d6 +030100f1efe30d0b00f7f5e9f1efe30d0b00e5e3d7f1efe3060400e9e7db090700f1efe3 +e8e6daedebdff7f5e9f0eee2030100f4f2e6faf8ecdcdace030100eeece0030100ebe9dd +fffff4dddbcfe1dfd3060400f3f1e5efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddde4f0d8eef0dbffe4de +fee2dfeeefe9dfeee7e7eff199969ffff2fff0ffff00260c0092622efdc5009871000f16 +ffe8e5fff0b0ffd57afffaaafbdc99120000140d000600000d060d0f0013fff6fffff6ff +fff8fffffbfdfffff6f2f7e3fcfff1fafdf6fffffff5f5f5fffffff5f5f5fffffffefefe +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffbf2fef0f5feffada7ff3126dc0e06b3dcdeffeef9ff0f1e6106107200086fe6eeff +e2e3ff2011e01b0ad2afaefff8fdfffcffffe7e7e7fafafa000000fefefeffffffffffff +ffffffffffffffffffecececfffffffffffff2f2f2fcfcfcf6f6f6f9f9f9fffffffefefe +edededfffffffffffff6f6f6fffffffffffffffffffafafafffffffefefeffffffeaeaea +ffffffefefeffffffffafafaf5f5f5fffffff2f2f2fffffffffffffffffffffffff2f2f2 +fffffff5f5f5fafafaffffffefefeffdfdfdfffffffbfbfb000000fffffff0f0f0ffffff +fffffffbfbfbfafafafdfdfdfefefefffffffafafaf4f4f4ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc70738db1c60f31c55bc +e0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefede0fbf9ecefede0030100 +e6e4d7e2e0d3f2f0e3050300e8e6daeeece0fcfaee030100e5e3d7f5f3e7dcdace060400 +eeece00a0800f1efe3efede1e7e5d9151307d0cec2151307faf8ecf7f5e9030100171509 +dbd9cd030100e1dfd3f1efe3030100f4f2e6fffdf1030100f0eee2030100e8e6daf6f4e8 +fffef2030100fdfbef030100eae8dcedebdffffdf1070500e5e3d70f0d01eae8dcf4f2e6 +0d0b00f5f3e7eae8dc030100efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddde6f0d8eef0dbfee6dcfbe3df +ebf0e9deefe7e6f0f198979ffff7ffedfeff0024104cf1c7009b684edbb800050bfff1f1 +ffe5b2ffeda1643f00ffffc3fbf5c5f5f9d8f6fbe7eaebe5070004fff8ffffeffffff0ff +ffecf30d0000060000fffff6fbfaf6fefefeffffff080808ffffffeeeeeefcfcfcf7f7f7 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +f5ffffb6c1f9160ebb0000d31001e2160ec4f0f5fff0fcffeffdfff0fafff0efff0f06c3 +0b00df0900cf0c0a91c5c7ffededffffffffffffff0a0a0afdfdfdf2f2f2ffffffeeeeee +fbfbfbfcfcfcffffffe9e9e9fffffffffffff9f9f9fffffffffffffffffff1f1f1ffffff +ffffffefefeffcfcfcfffffffcfcfcfffffff1f1f1f9f9f9fffffffafafafffffff0f0f0 +fffffffcfcfcfffffffffffff6f6f6fffffffffffffcfcfcfcfcfcfffffffffffff6f6f6 +fffffffffffffcfcfcfffffffffffff4f4f4ffffff040404fafafaffffffeeeeeefbfbfb +fffffffafafafbfbfbfdfdfdf5f5f5f9f9f9fffffffbfbfbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc70738db1c60f31c55bce0e9ff +f4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdffcfaedd5d3c6f5f3e6030100121003 +090700030100f1efe2f3f1e5edebdfe1dfd3efede10b09000f0d01030100efede1faf8ec +efede1030100080600050300efede1fefcf0e0ded2030100030100e4e2d6030100f5f3e7 +121004e9e7dbeceade030100f6f4e8e0ded20b0900fdfbefe5e3d7030100060400030100 +dddbcfe4e2d6090700faf8ecefede1e1dfd3050300f2f0e4fbf9ed030100eeece0e0ded2 +0c0a00030100fcfaeeefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeecddeaedd8f0efdbfae8dcf5e7dee8f2e9 +deefe7e5f0f29598a1f8eafbeff9ff00241b087c6553daba1c836e00050cfff7f6fff4c8 +ffffbf565616f6ffc8e1ffc9d9ffd0eaffeaeefff3000500fffffdf3e7ebfff8ff150208 +faebf0fffcfdfefaf9fffeffffffff000000070707f4f4f4ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffe4f6fa +c9d7ff0f09c10000d3200eff1508d1030478f1fbff142046dbe5ff110e992218db0300dc +1d11ed1a19b5aaadfff4f5fffffffff8f8f8000000fffffff4f4f4fffffffefefeffffff +f7f7f7f9f9f9ffffffecececfdfdfdfcfcfcfcfcfcfafafafffffffdfdfdfffffffcfcfc +fffffffffffff6f6f6fffffff7f7f7fffffffcfcfcfafafafcfcfcefefeffffffffcfcfc +f6f6f6fffffffafafafffffffffffffbfbfbf9f9f9f9f9f9fbfbfbfffffffffffffafafa +fffffff6f6f6fcfcfcf3f3f3fcfcfcffffff030303f8f8f8ffffffffffffffffffffffff +fbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001cc70738db1c60f31c55bce0e9fff4ebe2 +e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeae8dbeae8dbf1efe2fffff3d6d4c7f3f1e4 +eceadde7e5d8f2f0e4e8e6daf8f6eaf3f1e5d7d5c9fbf9ede5e3d7f7f5e9e1dfd3e5e3d7 +f4f2e6f4f2e6e4e2d6f7f5e9eeece0efede1f0eee2eeece0f1efe3efede1eceadeeae8dc +fffef2e8e6daf4f2e6f0eee2f3f1e5dcdacef8f6eae2e0d4fffff4dddbcfe5e3d7fffff4 +edebdff9f7ebe7e5d9e1dfd3fbf9edeae8dcf5f3e7dfddd1ebe9ddf3f1e5f3f1e5eae8dc +eceadee9e7dbefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefecddf0ebd8f3eedbf2ecdceaecdee6f3e9dcf0e7 +e3f1f29498a1fffbfffffcff00040e000e13000d0c000f11000813fafffbebffdee4ffd6 +c9ffc638884314712b207f3d00561c003403001400ebfff3f7fff8020401eeeceffffeff +f6f6fef5f8fdfeffffffffffffffff000000f7f7f7ffffffffffffefefefffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffff9fffff0ffffacbff9 +0506b01409eb0d00dd1006bff2f2fff2f8ff161968f2f7fff1f6ff0000771a0fe70000cf +0306a3c5ccfff9fcffffffffffffff000000ffffffffffff0000000d0d0d000000f8f8f8 +fffffffefefefffffffbfbfbfffffffbfbfbfffffffefefe000000080808000000000000 +fffffff8f8f80000000b0b0b000000fffffffafafaffffff000000070707000000ffffff +fbfbfbf4f4f40c0c0c000000000000ffffffffffff0000000000000c0c0cf4f4f4fbfbfb +ffffff000000101010000000f8f8f80101010000000101010d0d0df1f1f1fffffff2f2f2 +000000000000000000ffffffe9e9e9fdfdfdffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001cc70837db1c60f31e55bce0e9fff4ebe2e8ebda +ebf0dceeeddbefebdfefeae4f1eae4f5e8dff5e9dbefebdfeceddfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeceaddf8f6e9f1efe2dbd9ccfaf8ebf0eee1e8e6d9 +f9f7eaf3f5e8eaecdfdfe1d4ebeddff6f7e9e5e3d6f7f1e5eee5dcf5ece5fdf6f0e8e3df +e4e1dcfbf8f1e4e4dae8e9dbf5f3e6f3ece4ece5dfeeede8f5f6f0e5e6dee9e9ddf4f1e2 +f4eddbefe6d7ede3d7f2ebe1fbf7eee9e5dcf6efe5eae0d4faf1e2f4ede3eae7def3efe4 +e6e4d8f8f4e9f3f1e5ece8ddf0eee1e9e5d9f9f7eaeeeadef2f0e4ece8ddebe9ddf9f7eb +e6e4d8efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff1ebdff4e7def5ebdfefeddee7eedee4f4e7deefe7e3f1f1 +92999ffcf9fff9eefc100611030007fefeff00000b00010eedffffd6ffe6146f29167c3a +45b97a33b77e139b6900784c0e7852001700e1ffeaedfbea050d02000302010a0f00020b +f8fffff9fdfffefefeffffff000000fffffffffffff5f5f5ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffff9fffff0ffffb5c8ff0708b2 +140ae70700cdf1e9ff0d0f7ef1f7ffebeefff1f5ffeaf5ffeef6ff140dd50d07e30205a8 +b7bffff9fcffedededffffff040404fffffffdfdfdfffffff6f6f6ffffff080808f7f7f7 +fffffffffffff2f2f2fffffffffffffefefe000000fffffffafafafafafa040404fdfdfd +040404ffffffffffffededed0e0e0effffff000000fffffffafafafefefe000000ffffff +000000f9f9f9fffffffdfdfdfffffffffffffdfdfdfffffff9f9f9000000ffffff000000 +fefefef9f9f9ffffffffffff000000fffffffcfcfcfcfcfc060606f7f7f7090909ffffff +f1f1f1ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001bc70837db1c60f31e55bce0e9fff4ebe2e8ebdaebf0dc +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeeecdfebeddfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddf +e7efe0e4f1e0e4f1e0e7f0ddebeedbefecd9f5e9dbf9e6dff9e5e6f8e4edf3e5f2efe7f2 +eceaedebece6ebeeddefecddf9e7e5fbebeeedecf2dee6e9dee9e5ebf1e5f6eed7f6e5c9 +ffe7cfffe9d9f9eae5f1e5e5efe5e4f6e7e0fee7d5fce6d1f8ebe2f1ece6f4ede5f5f1e6 +f5eee4efebdfefe9ddefecddf1ebddefecddf1ebddefebdff1ebdfefebdfefebe0efebe0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff2e9e2f7e4e6fae7e9f2ebe1eaecdee8f3e3e1eee4e6f0f194999f +fffdfffffdff060000fffff8000200ecf5fa021222dcfffd156c2785f69c4abf7b038559 +008878007a7a007f85003d45000913fffdfffff9f3040000f8fffde8fcfbf0ffff00080e +fcffffe9e9e9ffffff030303f1f1f1fffffffffffff2f2f2ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffbffffefffffbccbff0f09c30200dd +0d05cceeecffedf3ff0f1978070e8019228bebfcffeaf6ff0000b90e09df0102b2bcbeff +f7f9fffdfdfdfafafa070707fcfcfcffffff000000000000000000010101fffffff8f8f8 +fffffffffffffafafafbfbfbffffff060606fffffff9f9f9fefefe0e0e0eeeeeee020202 +030303000000060606000000f5f5f5030303fffffff9f9f9fdfdfd090909ffffff000000 +fdfdfdffffffeaeaeaffffffffffff0000000000000101010c0c0cfbfbfb000000fefefe +fffffffffffff4f4f4040404f5f5f5fffffff6f6f60a0a0afdfdfd000000080808000000 +0000000a0a0afafafaffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0eaede2 +e7efe2e7efe0e7f0ddebeed9efedd8f5e9d9f8e7ddf9e5e6f6e5edf3e5f4efe7f4eee9ed +eeebe4efecd9f5ead8f7ded7f8e2e4eeedf2e9f4f6e7f6f3ebf3e6f5eed4fdeaccf9ddc7 +ffe6d9fceeeef3ecf3ece7edefe5e3ffebd8fff2ddefe2d9eee9e3f1eae4ebe7dcede6dc +f2ece0f5efe1f5efe1f1ebdbf1ebdbf1ebddf1ebddf1ebdff1ebdfefebe0efebe0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff2e9e2f7e4eafae7ebf3eae3ebecdeeaf2e3e2eee4e7eff195989ffffcff +fffdff040000040200f6fbf505101600031933646196fcba4dcf77007030058d69004743 +29d3e441edff51cde700031efff5fffff5f5120500fbfffdf4ffffe4f0f0000709fafbfd +fffffff6f6f6080808fffffffffffff6f6f6ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffcfffff5ffffabb4ed0c05ad1c0ee90c03ce +0805b6ebeeffe0e8ffeaf2ffd0d9ffeaf5ff0a11960502c11d1add0b0ca5babefffbfbff +ffffffffffff080808fefefe000000fffffffefefeffffff000000fffffffdfdfdf2f2f2 +ffffffe7e7e7fffffffefefe000000fffffffffffff5f5f5000000ffffff000000ffffff +f0f0f0f8f8f8ffffffffffff000000fffffffffffffefefe000000fcfcfc080808fcfcfc +eeeeeeffffffffffff000000fffffff6f6f6f3f3f3000000fbfbfb191919f4f4f4fafafa +ffffffffffff060606fffffffefefeffffff000000f8f8f80e0e0ef3f3f3fdfdfdffffff +fcfcfcfafafaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1eae0f3e8e6f3e8e6 +f1eae2eeecdfeceed9eceed8efedd8efecdbefebe2efeae7efe9ebefe9ebf2e8e6f5e9dd +f8e9d4fce8cfffead4ffe8d6f0ece1e7f1e9e0ede4dee6d9eae5d1f9ead5ffecdef3e4df +e6e3ece5ebf9eaf4fee9f1f3e8e6d7e3decbece8dff3f0e9f5f0eaeceadeebe7dcf1ede1 +f3f0e1eeebdcefecdbefecdbefecddefecddf1ebdff1ebdff1eae0f1eae0efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff2e9e2f7e4e6f8e8e8f2ece0eaeddceaf3e2e2eee4e7eff29498a1fffdfffffcff +030000010000000104000210011132002c3a00653900833f0b9258003e1448e5d44bf1f1 +33dae2004957000419fff5fffff1f80d0000fbf6faf9f9f9fffef6060000f5f4f0ffffff +fefefe000000fffffff3f3f3fffffff5f5f5ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcffffeef7fcf5fcffd6d2ff00009e0a00d70a00e2 +1008d91412cfeaecff1719c60000b41911e20500cb00009dbfc4ffe1e8fffafcffffffff +f5f5f5000000ffffff040404f7f7f7fffffffdfdfd000000f9f9f9ffffffffffffffffff +fffffff9f9f9ffffff000000fafafaf8f8f8fafafa0b0b0bffffff000000f6f6f6ffffff +ffffff000000ffffff000000f8f8f8ffffffffffff000000ffffff0c0c0cf3f3f3ffffff +f0f0f0f3f3f3000000f2f2f2ffffffffffff0f0f0ffafafa000000ffffffffffffefefef +ffffff000000fcfcfcf2f2f2ffffff030303ffffff000000fffffffbfbfbf1f1f1000000 +fffffff7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff2e9e2f9e5e7fae4e7f8e6e4 +f3e9dff1ecd9eeedd8eceed8ebeedbebeddfebede2eeebe4f1eae4f3e9dff8e8d8fae8d2 +fde8cbffe9c9f9eacbebedd8e3f0dfe2f2e5e8f4e6f6f5e1fdf5e2f8eadff3eae5e9eaef +dee7f0d5e4e9d6e5deeaf2dbfafee7eeeee2eeeee6eeeee6efefe3f0f0e4f1efe2edebdc +eae7d8efecdbefecdbefecddefecddf1ebdff1ebdff1eae0f1eae0efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f1eae0f5e6e3f7eae4f0eddceaedd8eaf3e2e2eee4e7eef49498a4f6f5fffffdfffaf8f9 +fefffff6fdff00091d000f36ceffff54dcc8009c750079553fe1bc4efad2009268009164 +098f6e00150ef5eaf0fffbfffffcfd0602010c06060d0000fff9fdfffdfff6f6f60b0b0b +000000000000ffffffedededffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffefffffbfffff0f4ffbabbfc15118a0e02c61c0ef70000d1 +0400d7e6e5ff0100bf1105ef0d00e4160bbd181588c1c8f2f8fffff1f2f4ffffffffffff +000000f8f8f8ffffff000000000000000000000000fffffffefefef1f1f1fffffff9f9f9 +ffffffeeeeeeffffff070707000000080808000000fffffffafafa0101010a0a0a000000 +fffffff0f0f0f3f3f30a0a0a000000000000fffffffbfbfbf7f7f7000000020202000000 +ffffffffffff000000080808000000070707fffffff5f5f50000000000000a0a0af2f2f2 +000000ffffffffffffeaeaea030303f7f7f7fafafa0000000e0e0e000000fcfcfcffffff +f6f6f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff2e9e2f9e4ebfce2ebfae5e4f8e7df +f5e9d9f1ecd8eeedd8ebeedbebeddfebeddfeeecdff1ebddf3ead9f6ead4f6ead2f6ebcd +eee6c1efefcbe5f4d7dcf2ddddf6e3e5f8e5e8edd9e2ddc9eee5d4f0e8dbeeeee6edf2eb +eff7eaeef8dfeef2cde9eac8f1f2e2e4e5dde0e1d9eaecdfeff1e4eceddfebecdcf2f0e1 +eeeddbeeeddbefecddefecddf1ebdff1ebdff1eae0f1eae0efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdf +f2e7e1f4ece1efeedae9eed7e8f4e0e2ede5e6eff69298a6fcfefff0f0fcfefffff6fafd +f8ffff000218b9c8f182c6eb32dfe618f0eb2df5f530f4de00ab6100a2341cf06722ca53 +001c00ecffeff4fffaf2fff5f5fff1f9f9f9fff4fffff0fffffbffffffffffffffffffff +f6f6f6fdfdfdfffffff7f7f7ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffefff3f3fbfbffffc5c8fd08048d0000b61e17f10601d7 +e7e7ff0a08c30a00de0000b7131077c6caf0f1f6faf1f7edfffffdedededefefefffffff +fffffffbfbfbfffffffffffff9f9f9fffffff1f1f1fffffffffffffffffff6f6f6ffffff +ffffffefefeffffffffcfcfcffffff000000e6e6e6ffffffffffffe5e5e5fffffff7f7f7 +fffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffff1f1f1 +f5f5f5fffffff2f2f2fdfdfdfffffff9f9f9fffffffffffffffffffffffff9f9f9ffffff +fffffff4f4f4fffffff7f7f7fffffffffffff3f3f3ffffffffffffffffffebebebffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc7 +0837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff1eae2f5e6ebf6e5ebf9e5e4f9e7ddf8e8d9 +f5ead8f1ebddeeecdfecece2ecece2f1ebdff1ebdbf1ecd9efedd8eceed8eceed6f5f0d2 +f3f2d6e7f0dddeeee1ddf1e8e5f6eeedf2ebedede5f5f0ecf6f2f1e9ecf1dce5eadceaeb +e5f5f2e5f3e6dce7d9f3f9efebeee5e6e9e0e9eddfeaecdfe7e9dbecedddf4f5e5eeeddb +eeeddbefecddefecddf1ebdff1ebdff1eae0f1eae0efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1e8df +f3eddfedefd9e9eed7eaf3e0e2ede5e6eff69199a6eff2fffbfffffafffff8ffffe4f2f5 +000313cadafe316d9100859429dee73ddfec0091850084412cd46527d74e46d45e001800 +eefffdedffffe8fff8f1fff3f9fff8f6e8fffff6fffaf4fef8f8f8ecececffffffffffff +fffffffafafaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffefffbf6fdfaf8fbfefff8eff4fff4f6ffb5b5ff000091181db7040d90 +0e149c0300abc5c0ffb8baedfcfffffffffbfffffafffffdfffffffbfbfbffffffffffff +efefeffffffff5f5f5fffffff6f6f6ffffff000000010101000000151515000000000000 +ffffff0e0e0e000000000000fdfdfdfffffffffffffcfcfcfffffffdfdfdffffffececec +f8f8f8fffffff3f3f3f2f2f2fffffff9f9f9fafafafffffffdfdfdfafafaffffffffffff +f8f8f8ffffffebebebfffffffefefef3f3f3fffffff3f3f3ecececfffffffafafaf4f4f4 +fffffff0f0f0fffffffcfcfcfffffffffffff9f9f9fefefeeeeeeeffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db +1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeebe2eaecebebebebf2e9e0f6e8dbfae7d9f9e7db +f6e7e4f3e7e7f1e8ebf1e8e9f2e9e4f1eae0ebeddfe4f1e0dcf4e6e1f1e6f9ece4f6e1de +f2e6e8f5f2f9eceefadbe1efe0e2f1eff0ffe5e7ffe8eeffc6d3fd8399c85472a65073a9 +5a7fb46280a6cedbe3e8eee4f4faf0ecf2e4e6eadce8ecddedf0dfedeedeeeeddbeeeddb +efecddefecddf1ebdff1ebdff2e9e0f1eae0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeadff0eee1 +edefdae9eed7eaf3e0e3ede4e6eff49199a4f8fffff8ffffe2efe6f5fff8f2fffd001215 +00041900071c00191e001112001619000b05001500001e00001b0000190006101cfefbff +e4f5ffe1feffeafff6e8ffe4fbffe6fdffeafafbf3fffffffffffff2f2f2f9f9f9f6f6f6 +fafafaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffefffffafffffafffffdfff5f7fff7fdffeffcffbacdf8afc7ebabc5deb5cbf2 +bbc4fff1f5fff9fefff1f0f5fef5fffff8fff8f5fcfffffff1f1f1f6f6f6ffffffffffff +fdfdfdfbfbfbffffffffffffffffffffffffebebebfbfbfbf5f5f5fffffffffffff5f5f5 +fffffff2f2f2fffffffcfcfcefefeffbfbfbf3f3f3fffffffbfbfbfffffffffffffbfbfb +fffffffffffffefefefffffffefefefffffff7f7f7fafafafffffffffffffffffffafafa +f3f3f3fffffff1f1f1fffffffffffffffffffffffffcfcfcf7f7f7fdfdfdffffffffffff +f1f1f1fffffffffffff0f0f0f9f9f9fffffff9f9f9ffffffecececffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff3 +1e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfebede2e1f0e9e3f0e7eeecdff5e9d9f9e7dbf8e6e2f2e7ed +efe7f4ece8f7ece9f4efe9ebecebe7e5efe7dcf3edd0f7f6d3f4fbe9ecfde6dcf4ebe9ff +f2f8ffcad5f18292ac61728c6a7d9b607495667da66b87b77ea1dbacd7ffc6f7ff94caff +5682c390a1b1d1d7cdf4faf0edf1e3e3e7d9eef2e3f2f5e4e6e7d7eeeddbeeeddbefecdd +efecddf1ebdff1ebdff2e9e0f1eae0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0edeae1eeeee2ecefda +e9eed8ebf2e2e5ece4e7eff2909aa3f5fffff0fffbf1fff2f1ffededfff0e6fff3ecffff +edffffe4fbf3f7fff6fefcedfffdeffff9f1fffcf9f4fffff2fffffdeefffff3fff5ffff +edffffddf7eef4ffedeef7ccffffddfefef2f6f6f6fefefeffffffffffffffffffffffff +fcfcfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffdfffef2fcfff9fffcf4fff8f8fff8fffff1ffffe8ffffebffffe8ffffedfffff1ffff +ebf4fffafdfffffdfffff7fffff7fffffdfffffffffffffff7f7f7fcfcfcfefefefcfcfc +fffffffffffff8f8f8fdfdfdfefefefffffffffffffffffffdfdfdfffffffffffff5f5f5 +fffffffcfcfcfafafafffffffffffffffffff6f6f6ffffffeaeaeafffffff6f6f6fafafa +fffffffafafafffffff7f7f7fcfcfcfffffffffffff8f8f8fefefef8f8f8ffffffffffff +fefefefffffffdfdfdf4f4f4fffffff2f2f2fffffff7f7f7fffffffffffff5f5f5fefefe +fffffffffffffffffffffffffffffff1f1f1fffffffffffff7f7f7ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc90534d81e60f42158bf +dfe5fff4ebe2edeedee9eedaeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeaeee0d9ede1dcf1e2e6e9d6eee7d5fef4eaf4ebece4e5f7e4ebff +d9e4ffe3edffeff3ffe3eaf0e5f4f9cbe8f05683965083a24f78a6587db25b83b43d6a93 +5c8cb0a8dbf8b4e8ffabdff491c1d583b1c85683a085b2db97caff88c1ff7dbbff4879bc +5467787e8178e8ebe2e3e5d8f5f7eaeaecdeecedddedeedeeeeddbeeeddbefecddefecdd +f1ebdff1ebdff1eae0f1eae0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0ebebe3edefe4ecefdceaedda +edf1e2e6ebe4e7eff2909b9fedfffc3f58457694703c60326f93656b8f697799816c937e +6fa18426553179986e84926f8c8678847e7ef4fffff7fffffff4fffffafff9fffff5ffff +fcfefff8edf3fffaeffffaedfff9f6fafafaffffffffffffffffffefefeffefefeffffff +f9f9f9fffffff8f8f8f1f1f1fafafaffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefd +fffbfbf4e9e7d8d0cd08080a00000c0a172800031700041c00022700032800011e00011a +050922f8f5fffffefff7f2eefbfaf8fcfcfcf9f9f9fffffffafafafffffffffffffdfdfd +fffffff1f1f1fffffff9f9f9fffffffafafafffffff7f7f7f7f7f7fffffffafafaffffff +f9f9f9fffffff1f1f1fffffff8f8f8fffffffefefefcfcfcfcfcfcfffffffbfbfbffffff +fffffffbfbfbfbfbfbfefefefffffffffffffefefef1f1f1ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc90534d81e60f42158bfdfe5ff +f4ebe2edeedee9eedaeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeaeee0eefff0e0f3e0f8fce5ede8d5e0ddd4eaf1f7e2faff5274995f85ac +5f80a15c6e826878857587955e798ea3cef0beefffb0ddff9cc7fc92bdea739fc46594b0 +6fa3b873abb88cc5ceaadfe3ceffffdfffff638fa883b3e189c0ff7dbeff4e80c54a5b6d +777870f0f0e8e8e8dcedede1e8e9dbe8e9d9eceadbeeeddbeeeddbefecddefecddf1ebdf +f1ebdff1eae0f1eae0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeece0ebeae5edeee6edeedeeaeddaeef0e3 +e8ebe4e7eff18e9c9df1fffb6a886c29511f78a4653e6c2c649156e3ffe06c9c74205f30 +68a77231602ae3fed5fefef297919500010cf7fefffff9fbfffcf8eff5f1f6fffffffaff +ffecfffff3ffffe4e9fffcfdfffffff2f2f2fffffffffffff3f3f3ffffffe2e2e2ffffff +efefeffffffffffffffffffffffffff9f9f9f8f8f8ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff8fc +fffbfb867f77bebdb80001050002100003174f61875160a148569757658c000822eaefff +000012fefffffffff8fffffdffffffffffffedededf1f1f1ffffffe9e9e9fffffffafafa +fffffffffffffffffff6f6f6fcfcfcf5f5f5fffffffffffff5f5f5fcfcfcf6f6f6ffffff +fffffffffffffafafaffffffdfdfdfffffffffffffedededfcfcfcfffffffbfbfbf7f7f7 +fffffffffffffbfbfbe9e9e9fefefeffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001dc90534d81e60f42158bfdfe5fff4ebe2 +edeedee9eedaeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeceddfd6decfebf2e2ece7d1fcf7e4fcfffd445c685186a694d8ffa2e9ffa3e1ff +b4d9f39eb8c997a8ba7f93ae7998c66f8ebd9fadd4a8adcad0d2e7eff3fff5feffeafcfc +e1fefae9ffffe7ffffe9ffffe5fffee9ffff43678b81afea8ac4ff2d5da54b576d75706a +f5f0eaeeeadfeae6dbf2eee2f0eddeeeebdcefecdbefecdbefecddefecddefebdfefebdf +efebe0efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeece0ebeae5eeeee6efede0edebdcf1efe3e9eae4 +e9eef18e9c9ceefffa466b49e4ffd8275d1263994b346a1f6fa1642f652b6ba966256121 +80af7be7ffe0fffffa867a84ecf0f9060910fffbfbfffdf6f7fff4f7fffbf6f1f8fff7ff +f5d9f2fff5fffffcfff1f1f1fffffffffffff0f0f0fffffffefefefffffffafafaffffff +f5f5f5fcfcfcf4f4f4fefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffff6fffff9ff +0400008b8c7ecdd5ca04110a0005050005224b53a8585ebc515e95000120f4fffff5ffff +000012fbfffffeffffeaeaeafffffffffffffffffff4f4f4ffffffffffffffffffffffff +f6f6f6f2f2f2fffffffffffff8f8f8fafafafafafaf8f8f8fffffffffffff2f2f2f6f6f6 +fffffffffffffffffffffffffffffff7f7f7fffffffffffffffffff3f3f3fffffff7f7f7 +fffffffffffffffffffbfbfbfffffff7f7f7ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001dc90534d81e60f42158bfdfe5fff4ebe2edeede +e9eedaeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecdff7f9ecdedfd1eee6d3efe9dbd1dbdc4d7285a2e9ff54afe46bc9fd70c1ec6da1b9 +91aebebbcbdbf2ffffd6ecffe9fffff1fffff8fffffcfefffbfbfffbfffff5ffffebffff +e5ffffe6fffeddfdeeeefffbe8ffffcdf0ff6591be6ba7ef4373b34d5568776e69f3eae5 +f3eae1ebe2d9f8f2e6f4eee0f0eadcf1ebdbefecdbefecddefecddefebdfefebdfefebe0 +efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeece0ebebe3eeeee4f0eddeeeebdcf2eee3eae9e4e9eef1 +8d9d9cddfcece4ffea225a1bd5ffc538762169a7542e6722629958275e1a72a664d1f9c5 +f4ffecfffcfd0c000d0706140000070d0200eae4d6f7fff1f4fff8fffeffece0f4fff9ff +fdf1fffcf9fffffffffffffff3f3f3fffffffffffff9f9f9f3f3f3ffffffedededfefefe +fffffffffffffffffff5f5f5ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffefffffafffff5ff030000 +0506007a8076c4d0c40008000004145b62b24046a8515ba0000531e6f7fff0fffff1ffff +000212fbfffffffffff4f4f4fffffffafafafefefeffffffecececfefefeffffffffffff +fbfbfbfffffff9f9f9fffffffffffffffffffffffff9f9f9fffffffbfbfbffffffffffff +fefefefbfbfbf4f4f4f5f5f5fffffffffffffbfbfbf6f6f6fdfdfdfffffff9f9f9ffffff +f4f4f4ffffffedededffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001dc90534d81e60f42158bfdfe5fff4ebe2edeedee9eeda +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0 +e3e3d9fbf7ecfaedddefe6ddf3fdff37607c7ecfff59c1ff43ade94faad94f899fd3f3fe +effdfff3feffedffffe3ffffc6f7ffd1ffffdcffffe1ffffe3ffffdbffffbdf0ff99d1de +8fc4c8bfeee6e3fff8e7fffde2ffffb8ecff3b7fac598eb8424a57827370f3e5e2fff5ed +f0e6ddf1e7ddf0e6daf0e8dbf2ebdbf1ebdbf1ebddf1ebddefebdfefebdfeeece0eeece0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecdfebebe1f0eee2f2ecdcf0eadaf4ede3ece8e5eaedf28d9d9d +eafffbe2ffeddcffdc286c1fd5ffc6357828528f4c3c6f346b935eebffdaeeffdaf7ffe6 +fcf0f4fff0fffffaffbbb8c9080000ffffeae9ffe3effff5eaf3fcf9fffff7fffff7ffff +fcfffffffffffffffff4f4f4fffffffffffff4f4f4fffffffdfdfdfffffff9f9f9ffffff +f5f5f5fdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffaffffedffffee08060b02000d +05080d000300e9f6e2c3d1d1535d924d54a45661b000014100092d000619001721000d11 +f9fffff3f3f3ffffff000000fefefef7f7f7fffffffffffffffffffbfbfbfdfdfdffffff +f8f8f8fffffffffffff8f8f8f8f8f8fffffffffffff8f8f8fffffffdfdfdfbfbfbffffff +fefefeffffffffffff000000fffffff8f8f8fffffffffffff7f7f7fffffffefefeffffff +f8f8f8fffffffffffff7f7f7ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001dc90534d81e60f42158bfdfe5fff4ebe2edeedee9eedaeeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0e0e3da +f5f5ebf5e9dde3dad5ebf4ff355c837bcaff3da3ee4bb4f8419dd097d0e4e9fffff5ffff +f7ffffebffffd5fcffd5ffffbef8ff98c5da84aac17b9ebc7da5c897c9eea4d9f990c3d6 +77a3a6ddfdf0edfff8dafbf2d6ffff9edef92b5d783b3f4a8d7978e1cfcdfff6effeefe8 +ebded5f2e6daf5ebdff3eadbf2ebdbf1ebddf1ebddefebdfeeecdfeeece0eeece0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfedebdef0eedff2edd9f1ead8f6ece2ede8e5eaedf48d9c9fe9ffff +c8fbdc18591f65ad631b6415d6ffd12f6f325d925c5179476586593e6236ecffe9fff9fd +fff7fffffbffc9c8d6070000fffff1f4ffeff1fff6000908070e14000604edfffcf8fefc +0000000303030a0a0a000000000000ffffff000000000000000000000000000000ffffff +fafafafffffff9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffff6ffffe4fcffe700000500001000000b +c8cbd0f9fffff7ffffbac6e0707daa4c5c9a364a8950699f44648a446a81000912edf6fb +ffffffffffff000000fafafafffffff1f1f1ffffffffffffedededfffffff6f6f6ffffff +f6f6f6fffffffcfcfcfcfcfcfffffff6f6f6fffffff6f6f6ffffffedededfffffffdfdfd +ffffffebebeb0b0b0bfefefef8f8f8fffffffbfbfbfffffffefefefffffffafafaffffff +f8f8f8fdfdfdfbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001dc90534d81e60f42158bfdfe5fff4ebe2edeedee9eedaeeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfebede0ebf8eee4eee5 +f6efe5f5ecede7ecff3958878ccfff54aeff3a97e464b5ecdbffffe4fefbe6f6ebf4fffd +81a3ad90baca90b6bfafcdd5cbdce6f7fefff8fdffecf5ffe6faffd8f2ffbed6fc8a9bad +dce2e0fefff4f8fffae3fdfcdaffff385e7144414a816c6b978281dac5c0ffede7f2e1d9 +fceee3f7ebdff3eadbf2ebdbf1ebddf1ebddefebdfeeecdfeeece0eeece0efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddedebdcf1eedbf3edd7f2ead7f8ebe2efe7e5ececf48d9ca3e2fffe356a50 +6bae79236e2b58a45c28712cd3ffde356f3d5a8d5538693a689880e7fffff8fffffffeff +f8fefebfc3c409000afbeff9fbfffb000600ffffedf9f6e5f9fffd000708fcffffffffff +fcfcfcf6f6f6ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffaf1f5e6fefff405060b00000bccccd4cdcfde +f0f0fff4f9fff2ffffcee2e0697f944f67954460a94465b22e569100193ef7ffffffffff +efefef060606fcfcfcffffffedededfefefefefefefffffffffffffafafafffffffefefe +efefefffffffffffffefefeffefefefffffffafafafffffffffffffefefef9f9f9ffffff +fafafa0d0d0df6f6f6fffffff8f8f8fffffff6f6f6fefefefefefefffffffbfbfbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001dc90534d81d61f42158bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeeecdfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfebede2ddeae1e9f4ecf0e9e1 +e8dde1f1f3ff4b65967dbfff499ae93681bbc9ffffe5fffff4fff6f9fff1f1fff87399a6 +dfffffe2fffff0fffff3fafffefbfffff8fff6f0fff6f9ffdae5ffc3d4ff798aa4eefbff +eefaf8e7f7f4e5fdffc1e5f3576e7c534248704e4d492a27a0837df7ded7f8e4dbfff2e8 +eee1d8f3e9dff2eadff1eae0f1eae0f1eae0f1ebdff1ebdff1ebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecddeaeddaf0efdbf6ebd7f7e7d8f8ebe2ece8e5e6f0f2879f9fe7ffff699681245b33 +5c98652d6c35569560366f44d6ffe237713659925d265e43defffdf0fffdf6fff9f6fff5 +c6cdc606000bfff9ffffffff000200fffde6fffae5fffffa000103fffffff8f6f7fffdff +fffcff030004fffdfffffcfbfdf9fafffefff8f6fb070709fcfcfcfffffbfffefcf1eff4 +fffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffefffffcfffffaffff00000e060d1d7b838ebac2d5c5c8f1 +f8fdfff7fff4eafde1c0d3d16d82a14960a6435fb2466db2000532f4fffffcfcfcffffff +000000fffffff5f5f50d0d0d000000020202f8f8f8fefefeffffff000000020202080808 +fefefefefefe080808020202000000fffffffefefef8f8f8020202030303000000ffffff +000000030303000000000000ffffffffffffe8e8e80a0a0a070707000000fffffffefefe +f8f8f8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001dc8002fd32064f71a51b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4 +f5e8dff5e9dbefebdfeceddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfecece2e8ede9edededf5e7e6f7eaf1 +e6e7fc44618984caff2e7bafbdeffaddfae8f9ffe4fbffdcffffebf3fdff85a3c9ddffff +dbffffe6ffffeefffff5fcfff7f4fff1edffeceeffe0f0ffb4d5f66f9db7ceffffc4f9ff +99c9d7446b7a496676d2d6e25d39399a655f8b5b518e665af3d3c6fff1e5f8e7ddf2e7e1 +f2e8e6f1e9e7f1e8e9f2e8e7f3e8e4f5e8dff8e8dbf6e8dbf2eaddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfebeedd +e4f0daecf1ddfae8dcfbe4dcf8ebe5e6ebe4dbf7eb7fa598e7fffb345343768f7a415d44 +71947637603e6e9779305f35dfffd823601d68a16c316137eaffecf0ffefe7fde8bfcdc0 +000100f4f2f5fffffdfffff80901000b0100070000fffef8fffffafffdfffff5fffbedff +0c000ffff9fff2e6e6fffcfdf8f0fdfffbff0e0b12fcfcfafffff5fffefbfbf0fffffaff +fffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffefffffcfefff8feff0000205a6d8b445d737a94a1b9ced1bccdc3 +fbffe8feffeafefffdf7fcff6b78a4576ea434588a000629f3fdfffffffffefefe000000 +fdfdfdfefefefffffffdfdfdfbfbfb0a0a0affffff000000fffffff7f7f7fffffffbfbfb +fffffff8f8f8fbfbfbffffff000000ffffff000000fcfcfcfbfbfbfffffffafafa030303 +fffffff1f1f1ffffff000000fafafa070707fffffffafafaf6f6f6030303fafafaffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc8 +0030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeebe2f0f0eeece8e7f2e2e2f7ebefe4e7f8 +3c5d8084cdff4994bed8fbf5f5ffdcffffd6fffcd2fffee5f3fbfe81a1caddffffe6ffff +dff9f6f2ffffeef8ffe8eafff5f9ffddebffc7e1ffacdafb5a96b8387ea0498db26ea8ce +c1eeffa4c1e9aaabc9a17a7f612821612f24865c4effebdce7d0c2f9ebe0f8efe8efeae7 +eeeaebefe9ebf1e8e9f3e8e4f6e7e0f8e8dbf6e9d9f2eaddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfebeddfe0f2dc +e9f2dffbe7e0fee2dff8ebe5e3ede2d7f9e87ca794e7fff8f2fffbebf5ecf7fff66a7f6e +eefff4d6f3dd7da0802c58275f8e57335d2d759a71001100d3edd4f4fff6c3d0c7040a08 +feffffffffff010000fffdfafcf7f1fffff6030100f6f8ebf5f5f3fff9ff0f001dfff9ff +fff6fbfffcf6fff9f6fffcff00000bf0f1f5fcfffaf6f9e8fefef4fffbfffdf4fffffdff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffefffffafbfff6fcff0006333951815978a40006256c8b90bbd3c6becab4 +040700030000fefdffb8bee25264925373a400072df2fcfff7f7f7f6f6f6161616ffffff +f4f4f40e0e0e0000000c0c0c000000fdfdfd0c0c0cfffffffffffffffffff2f2f2ffffff +040404080808060606000000ffffff010101fffffffffffffafafaffffff000000fbfbfb +ffffffffffff020202ffffff0000000000000303030d0d0d000000f9f9f9efefefffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d3 +2064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeece0f2f1ece8e5e0f1e4dcf9efede5ebf7375a7a +7dc8ff579fd1e8ffffffffedffffdffff6d4fffce4f3fefa80a5bfdeffffe6f1f7fffefb +fcf8f7f5f6faeff7ffdcf1ffd5f8ff95c5eb508bb75190c36cabe1bdf8ff96c8ff80abf9 +5a80d55e6dae674e636c403d7a554dffe2d7f0d9cbfffcece2d8cce9e5daeeebe4ecebe7 +eeeae9eeeae7f1eae4f2e9e0f3eadbf3eadbf1ebddefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfebeddfe2f1dce9f2df +fbe7e0fee2dff8ebe5e5ede2d8f9e87fa693e8fff5f5fffbf8fdf6fcfff8859686ebffee +f1fff4e3fae6f4fff4091a08f7fff6edf9ef000601f9fffffbffffbcbfc4000005feffff +f5f9fc020607fbfffef9fff9e7eee6040f01f8ffeff9fff4eceff600000bfffdfefffff6 +fefdebfffff3fbfffe000608f8fffbeffeebf9ffeaecf5e0fafbfdfffeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffefffff0f4fff5ffff0004384960a633509e5172b90004337c94aeb9c6ce82878a +01010dfafcfff4fcff3b4e883b589a000137f7fffffafafaffffff000000fcfcfc0c0c0c +f6f6f6fffffff8f8f8090909ffffff000000ebebebfffffffdfdfdffffff000000ffffff +e9e9e9ffffff060606fcfcfc000000fdfdfdffffffeeeeeefbfbfb090909f4f4f4ffffff +e7e7e7000000fcfcfc040404fffffff5f5f5f9f9f9ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f7 +1851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeece0edede3e9e7dbf4ebdcf6f2e9e5f2fa39607d73bffb +5097cfecfffffffbf1fffae2fff2d6fffee4f6fff77dadb7dcfffff7fffffaf1f4fcf2f1 +d7d3d2eaf1f7d5ecfc5e8bac538dbb92d5ff9ddfff9ad5ff84b8f45b88c93e6baf6797e1 +34528e3e344c7a6061fae2def9e7ddfff3e6e3dac9ffffefeeecddecece2ebece4ebece6 +ecebe6eeebe4eeece0efecddefecdbefecddefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfebeddfe3f0dceaf1dffbe7e0 +fce3dff6ebe5e6ece2dbf7e883a493f1fffaf0faf2fffffaf4f7f0808e81def0e0f5fff6 +f8fff8f5f7f6fffeff0100040100040b060df7f4fbf9f6ffc8c5ce08070ffefefff5f8ff +060b0ff9fffff8fffff0fcfa011107f5ffeff6fff20c1212f5f8fdfbfcf7fffff4ffffef +f5fcea040d08e5f1efeafaeff5fff3f7ffecf9ffeffcfffdfeffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffdfbfffbf5ffff000030475da9405cbf3f5dbf405dad00013a7d8dafb8c3d9bfc5dd +00001ef2fdff596da2375490001646ebf2ffffffffffffff000000ffffff000000fafafa +ffffffffffff090909ececec0b0b0bfffffff7f7f7fffffffcfcfc0d0d0df9f9f9ffffff +ededed070707fefefe000000fffffffffffffffffff5f5f5151515ffffffeeeeeeffffff +000000ffffff030303f8f8f8fdfdfdffffff020202efefeffafafaffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefede0efecddf8f1deebebdfe2f4f8416d8873bffd4d91ce +ebf9fffff3f3fff3e5ffeed7fffde2f4fff375b0accdffffe9ffffe8effffbf9fcfffefb +d7d8da7e909e527ca277b3e99fe3ff6cb0f1447bb134658d90bed5c3f4ffd5ffff29555e +323a45887e87eae4e4f4efe9e6e4d7e7e6d4e9ebd6f4f5e3ebeeddebede0ebede2ebece4 +ebede2ebede0ebeddfecedddeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddfe4f0dcecf0dffbe7e0fce3df +f6ebe5e6ece2def6e887a293f8fffbfefffbfffefbfffffa79837af7fff8eff9eeeef0eb +fbf6fa0d030bfff6fefffbff070002fffafffffcffd3ccd3030004fffdfffffeffececf6 +03071200071100010ceffafef8fff8e8f4e8000306fefefff9f8f6dfdfd7fffff4fefff6 +000104f8fffff2fefcf1fef4effae9f1f7ebf8f8fafaf7feffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefff8 +fcffe8f1fff000012242599f3d59bd516fdf4562c84963b800003e7583b2737ca5c9d3f7 +000025edffff506d8d00041cf7fffffffffff3f3f3060606fefefeffffff080808000000 +060606000000fffffffafafa040404101010000000ffffffeeeeee101010000000121212 +000000fbfbfbffffff0000000000000b0b0bffffff000000fffffffffffff7f7f7000000 +f6f6f6ffffff0000000d0d0d000000f4f4f4fffffffcfcfcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff3f1e2f2efdef7f2dee0e4d6dcf1f643729071bfff5799d6ecf6ff +fff0eefff2e2ffedd1fffbddedffec6baca6c2ffffbfe8feeeffffd1d8def0f6f667767b +0007194c83aa2f72a72267a03b75a5a1c6e1e5ffffebffffd7fff2d2ffff5b928f1e3441 +757b89e7ecf2dde2def9fcf1eef1dee4e7d2e0e2cceceddbecedddebede0ebede2eaede2 +eaede2e8eee0eaeedfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeceddfe6efdcedefe1fae7e1fbe3dff6ebe7 +e8ebe2e0f4e88b9f94f8fdf7f7f3f2fbf5f5f0efed87908bf8fffbfcfffdfffffffffdff +030005120b12040002040000fffdfb060000ccc4c2040000fffdfdf1ecf0fffefff5f4fc +fafafffcfefffbfffff4faf6fcfffbfffefffbf8fffffdfffffefaf3f0e9fffffbf9f9ff +fbfffff9fffffbfffffefffafcfbf7fffcfffffcfffffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6feffe8 +f1fceb00031c5b6fae3b55b22847b13754ba425db83b519c5565a3606ba14c5483bfcbf3 +00021e41586a061a23f9ffffe0e0e0f6f6f6fffffffffffff2f2f2fffffffcfcfceeeeee +fffffff8f8f8fbfbfbf6f6f6ffffffedededfffffffffffffffffffafafaf9f9f9ffffff +fffffffffffff6f6f6fffffffffffff8f8f8fdfdfdfffffffffffffffffffffffff6f6f6 +ffffffeeeeeeffffffebebebfffffffffffffefefeffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddf3f0dfedead7f7f2dfe2e5dcdbf2fa3a688a62b0f05a9bd5eef7fffff1e6 +fff3d6ffedc7fff9d6e9ffea66aaabbeffffd7ffffdcf7ffd7eff3d0eff290c1cf6db0ca +80d8ff73caf593d6f385adb7dde1d2fff9def5f3daeffff7c2faff437f991f3d57728196 +eaf8ffd3dfdfe4ece1edf1e0f5f7e1f0f0d8efedd8efecdbeeecdfecece0ebede2eaede2 +e8eee0eaeee0eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeceddfe7eedeeeefe1f9e8e1f9e4dff5ece7e8ebe2 +e3f3e8909d94fefdfbfffcfffff6fbfffeff7b8483b8c2c1cdccd1cccbd0c3cad0a1aaaf +d5dddfcad0cebec3bccccfc4050600c7c5b6070400fffff0fffef4fffef8fffdfbfffafd +fffcffefeaf0fffefffffefffcf5fcfef3fbfff3f7fffbfbfffaf9fffdfffffcfffaf8ff +fdfbfff9f8fefffafcfff9fafff8fffff2f9fffeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbeeeee6fcffff +000020404f88576eba526ec13352a24663af5970b64554993b4489595f9d5157894b5578 +586875000407fbfffffffffffffffffffffff9f9f9fffffffffffffefefeffffffffffff +fffffffafafafffffff5f5f5ffffffffffffffffffefefeffcfcfcffffffffffffffffff +fdfdfdffffffeeeeeefdfdfdfffffffffffffbfbfbf5f5f5fffffff7f7f7fffffff9f9f9 +fffffff6f6f6fffffffffffff5f5f5fcfcfcffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecddeeebdae6e3d2f8f2e2eceee9dff5ff2c59804d9bdb5293c9edf6fdfff3d9fff5c8 +ffecbdfff6d0e8fdea67a9b5c1ffffc5f5ffd6f7ffc9e7f1cbf1febcf6ff62b0d43698c7 +7cdbff98e0f8729899ede9ccfff6cffff6dcf6fbf7caf5ff5e91be2240645e728bd4e6f4 +f5ffffdbe5ddeff3e2e5e4cff3efd6f2ecd6f2ebd9f2eaddefebdfeeece0ebede2eaeee0 +eaeee0eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecdfe9eddef0eee1f9e8e1f7e6dff4ede5e8ebe4e6f1e9 +929b96fdf7f9fff5fdfff8fffefeff7a878d0003090b0b1500000b000511000c1600070e +000505000500000700000500060b00000400ffffedffffedfffcf0fffff6fbf6f2fffdfd +fffdfffffefffcfbfffffdfffffcfffff8fcfffbfffffcfffffafff5f3fffefdfffcfbff +fffdfffffdfffffbfffff2f8fffafdfffeffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffefffffdffefebf9050827 +00002b00003200063700052e000a3000022b00093700003300033a00002b000021040a16 +000104feffffedededfdfdfdfbfbfbfffffff7f7f7fffffffdfdfdfffffff8f8f8f8f8f8 +fffffffcfcfcfffffffdfdfdfafafaf8f8f8fffffffffffffffffffefefeffffffeeeeee +fffffffffffffbfbfbfffffffcfcfcf7f7f7fffffffffffffcfcfcf5f5f5ffffffffffff +fafafafffffffffffffafafaffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eeda +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdd +f0efdde1dfd0fff8eee3e4e8e1f3ff35608b3c87c85ea0d0f5fff9fff0c4fff7bbfff6bb +fdf4cbebfff36ca8c4b5feffc4fcffc6efffcae6fcc7e5ffb4deff91cdff6bbfff5db7f3 +73c0ea78abbcdbe9dcf7efd8fff6ebf7f4fdaabfec3f5e952a416a61728ee2f2ffdbe6ec +e9eee8eff0e2f7f2deeae2cbf5ead6f5ead8f5e9dbf3e9dff1eae0eeebe2ecece2ecece0 +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecdfebecdcf1eedff7e9e0f5e6dff2eee5e6ebe4e7f1e9959998 +fffafffff7fffefafff8fffff0ffffecfefffbfefffbfdfff1ffffeafefff0fffff1ffff +effefff5fffff5fff6f2ffedf8fff0f7ffebfbfff1fbfff4f7fff4f0f7f0fbfffdf9ffff +edf6fff4fcfffbfffffcfffffcfdffecedf1fcfffff6fdfff7fffff5fffff5fffff8ffff +edeffbfffdfffffcfdf9f1effffffdffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffefffffafffff6fffffbfff3f7ff +f2ffffeeffffe8fffaebfff8eefff8eafffaf5fffff9fdfffcfcfffffbfffffdfff7f6fb +fffffffdfdfdfffffffffffff3f3f3fffffffafafaffffffffffffffffffffffffffffff +fffffffffffffffffffffffff6f6f6fffffff4f4f4fffffffefefefffffff3f3f3ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdff3f4e4 +ebe9dcede4dff1eef7e0eeff47709e2f79ba4a8ebbe4f9eafef4bffffab7fff6b4fbf4c8 +e8f9ef6ea3c5b2f4ffb9efffbde9ffc9e4ffcce4ffbdddffa0ceff7dc0ff72b9f79ad8ff +658f9be8f5e4faf5dfebe7dee8f0ff3458922851931d3460657390ecf7ffe6edf5eaece7 +ebe9dcf7f0ddf5ead6f6e9d6f8e8d8f6e8ddf5e8dff3e9e0f1eae2efebe2efebe0efebe0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfedebdcf3eddff6e9e0f2e8dfefefe5e5ece4e7f0eb95999afffbff +fff9fffbfefff1ffffe9ffff18334618213e2225462c3755172540303f56263646202e37 +f2ffffeffffcf4fffff4ffff8b9c965e716f8fa2a6566d7595adb9465d6d879db45e7594 +889dba45576b8fa1af5868779cadbf50627a889db8445e777792ad3e57759fb4d35c6b88 +8a95a94e555dfcfffffeffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffefffffcfdf6ebf1fffcfffefdfff4fdff +eefff9f1fff1e8ffdfecffe0f5ffececf7efedf0f5fffdfff3ecfcfffcfffffdfffaf8f9 +fffffff8f8f8f7f7f7f9f9f9fffffffffffff8f8f8ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffdededefffffffffffff3f3f3fffffffffffff9f9f9ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdff1f3e6ecece2 +eee3e1f3ebf6e6ebff4567971f66a83178a6defaeefbfbc9ffffbefffdbdfffdd3e3f0e6 +79a6c5c6fdffbeedfdc1e7f2c5e1f9c5deffbbdaffadd2ffa4cfffa7cfffa6c0cf869181 +f3ecc2fffbd1f0feed75a2b70e63a61769b5163665717894eef4ffebeef5edece7eae6da +f7efdcf8edd9f6e9d8f8e8d9f8e7dff6e7e0f5e8e2f3e8e2f2e9e2f1eae0efebe0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeebdcf3eddff6e9e0f1e8dfedf0e5e3ede4e7f0ed95989dfff5fffffaff +f5ffffe5ffffdbffff1e46609badd3b3b9dd9a9eb79699aaa1a4b3acb2be272f3a1c2630 +f4ffffe3f5ffeeffff415b744f6e8d40638b3c6293325d945c88c52f5b9c3b63a8375f9d +4e74a34b71983f628c476c993b6097466fa74a75aa3f6da1446ea83a619c4e6ea7415c8b +92a9c8dff1fffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffff8ffffea918a788a84888c879b82829e676c82 +868f947f8c8375827084917d969d958789887f7d829790977b7074918889858384ffffff +fdfdfdfffffffffffffffffffffffffafafaffffffffffffffffffffffffffffffffffff +fffffffffffff9f9f9fffffff6f6f6ffffffffffffedededfffffff8f8f8ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfecece0e8ebe0e6e7dffff3f0 +ebdee5efefff3f5a89175ca1246b9fe7fffff7ffdef2f2befbf8c3ffffdce4f1e081a4b8 +b1e0fabbeaf0bee7e9bfdfeab8d2e9a9c1e598b0d68ba3c58c9dadbfc5b9cfccabf2eabc +f9fad8accac8004066076dc20059b21d3d6c7b7d92e3e5f2eae9eef1eee7efe9dbf3ecda +f2ead7f5e9d9f6e8ddf6e7e0f5e8e2f5e8e2f3e8e2f2e9e2f1eae0f1ebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecddf0eadaf4edddf4eadeeeeadfeaf2e5e1eee5e6f0ef95989ffffbfffefcff11253e +1a425b0038530436592d48778995bdaeafc1adaab19b9aa09da0a7222631afb6c6212d43 +f0ffffeaffff81a0cf4468a4406bb04574c42c5fb8336ac7356bcd3d6fd2406fc74273b8 +184984416eaf3d6cb23b6ab83467b63f75bf2c64ae3267b53667b6315aaa4c6fb33a5b88 +ebfffff8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffff6f7f8d97e7c65c6c0cabcb2d7e2d9ffc4bcf7c9c6f3 +bdbcdcc2c5d6bec2cdbcbecbb2b1bfdfdbeac2bac7dad0d8867d820a0809f1f1f1ffffff +fffffffffffff2f2f2ffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffff8f8f8fefefef7f7f7ffffffeaeaeaffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfecece0e4ebe3e4e7defff2e9efdddb +f6efff6b81aa195ca2276eaed0f6ffeefff7eaf2daecf0cdffffe1f0fae195afac84afb5 +73a9ab78aca885ada497b1a4aebdaac8d0b8e0e5c5eef3cbfdffd5eff6cceaf3d6d6ede7 +406b8d2363ab0259ca0e57be1c3261817f8ddedde3edeceaf3f0e7edeadbf0ebd8f2edda +f2eaddf2e9e0f2e9e2f2e9e4f2e9e4f2e9e2f2e9e2f1eae0f1ebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdd +f1eadaf4edddf3ebdeebecdee7f3e7deefe5e5f1f19299a3fffcffe7ebff0f2d496194b1 +2f74933c7ba4143c704d608b474b56aeada9a4a4a4afb0b42f333eabb3c68694b1192b53 +dff6ff4f6dad375caa3f6bc22c5cc03468d51c55c6447df12659cf2e5eca3c6ec3487cc7 +3566b5396bc03c6ecd275dbd235cb3437cd3386fca396bca436ecd456abb7495cae7ffff +f8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffafeffef959891cdc8e809003d0d005808005c0f00610e0258 +0d054e00003a150f4b1a154b0a04300d0628191126837d89010004fffffff9f9f9fefefe +fefefef8f8f8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffdfdfdfffffffffffffafafaf5f5f5fefefeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001ec9 +0435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfecece2e8f2eae8eee4efdfd0fce8ddf5eaf0 +becef01b59a22870bc6d98c5c8def3f4fffff5fdeef5f8dbf6fddbcce0c7a6c7b6b1dcd3 +b7e4ddc8ecded6f2dce3f7dbecfcd8ecfbd4e7f5d1edfcddbacdbaa0b9b66d8ca1042c5d +25559f003091002176303d5f979299e4e2e3f4f4ecf1f2e4e8e7d5ebead8f6f4e5eeece0 +efebe2efeae6efeae6f1eae4f1eae2f1eae0f1eae0efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf2e9da +f5ecdbf2ecdceaecdee4f4e7dcf0e7e3f1f19199a4f4f2fff5feff1f4665407fa04090b3 +337daa002f6990acdc9ea9bba5a9ac969ba1afb5c11a2134222c47303e61273967294076 +718fcf4f73bd2e57a94370cb497bda2359bd275cc63c6bdf3766d03463b32e5fa2416fba +3867b92756b24174cf3b72c42d66b53165bb3362ba375eb94163ad43638cedfffff9ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffefffbeffaec808988c1c0e00300370f005314015d0d0056190c5e1c115d +f7f0ff070245f9f5ff00002bf5f4ff1211217c7b81000002fffffff9f9f9fcfcfcffffff +fffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffff1f1f1 +000000fffffff8f8f8e9e9e9fffffff5f5f5ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001ec90435d8 +1d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfebede2e8f3ede7ede3f1e1caffe9d4f3e4dfedf8ff +104b971b62ba1b488b6c88b7bbd0ebe8f6f9f0f4dbf3f9cdf8ffd7e6f8cedbe8d4e6f3ec +e8fefbdefefdc7eff1a3cfd877a5b4568398254e6a173e5f1b3d6315305b253a6530416c +4d5a84656b8b898794ccc6c8edeae5f0f0e6eeefdfe8ebd8e8ebd8eff3e4eaede2ebece6 +ebece7ecebe7eeebe6eeebe2efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf2e9d8f5ecdb +f2ecdce9eddee3f5e7dbf0e7e2f2f29199a4fbfdfff2ffff0023444c92b40f678d4fa3d2 +02397987abe7889ec3b0bed945547191a0bf92a0c39cabd29fb1d991a4cf112756526c9d +3d5b8d4a6ea2d1f6ffc9f2ffd9ffff4874b53f64bddbffffddffffd7ffffdbffffddffff +3f66abd9ffffd4ffffd6ffffd9ffffdcffff4764a64b63939cb2c0e6f6f3fbffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcfffff5fffd768685b9c0d0888aa3938eac8a84a07a7289837e927f7d93797a98 +8082a9777ba19499b78086966670688e9689000100fffffffefefeffffffffffffffffff +fafafaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +fffffffffffffffffffefefef5f5f5ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001ec90435d81d61f4 +1f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfecece0e7ede3e3e5d8fff5e2efddcfece3e4e6f5ff063c86 +1051ad0f3e900d2f7646659cb4cbede8f5fbe6f2e4f1ffe8e4f2d9cdcec8b1b2b677858e +3f5b691e445714425c0f40600c3c6219436d3456834b6691687aa0747b9878768b7e747d +efe3e7e8deddfffbf7f1ede4e6e4d8ecedddeff2dfe9ecdbe6eadbeaede2eaede4ebece6 +ebece6ecece4eeebe2efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf2e9daf4edddf0edde +e9eddee6f4e5deefe5e5f1ef919aa3f7fcffeffeff0d36563773974d98c2276ea2033678 +88b0ee94b5e089a7c93c5d7e97bada8fb3d396b9d989aacd95b3d71c385d829cc14e6a8f +e3ffff4e70954a70943e6b8cd6ffff3f65b63a5faf466c9b42688c456b98ddffff3b63a8 +406baf3e699e4771a1386197d6faff4d6aa6516691526164f9fff8fefffdffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffff4fffa7b8a87c6cfd4fcfffff3f3f5fffff8ffffedffffe8ffffecfbfef3fbffff +f9ffffe7edf9f9fffff9fff6818a79000100fffffff6f6f6fffffffdfdfdfffffff8f8f8 +fffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe000000fcfcfc +fefefef2f2f2fffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001ec90435d81d61f41f58bf +dde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1ebddf5eedef4ecdff4ebe4e7e5eadee9ffd4ecff032f762e64ba +0a3c9504338b022c822e549f87a5e3849ed15d75a12a3e63323b5a1a213b2f39522d3c51 +3b4d615568794c5f6e6b7d896e7f8966737c8a919bd2d5defaf7fef0eaeee9dee2f4eae9 +f1eae4efebe0efebe0efebdfeeecdfeeecddeeecdfeeecdfeeece0eeece0eeece0eeece0 +eeece0efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeadef1ede1efede0ebecde +edf1e3e6ece0eaefe9949a9af5fcfff4ffff142e4917395e0b34620d35700b30748cb3ee +80aed08bbfd57bb8ca30748118606c195f69296877174c5e09314a4f6e8b576f93e1fbff +4a6c92446e943a6e95d2ffff3c6fca2d5cb64770a84e77a5cffbff3768b54274d33164bf +3a66ad4a71b2d7fdff4367b34262af536ca48a97a0fdfff7fffffdffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffb +f6fef1828981c0c3c8fffefffffafefffff3f5f3cd85854f7c7d43040700ffffe3fafdec +fefffbf6faf9fcfffa7f847d000000fffffffdfdfd0000000a0a0a000000fdfdfd030303 +020202f8f8f8ffffffffffff000000111111010101f3f3f3ffffff020202f6f6f6ffffff +020202fefefef9f9f9020202080808020202f1f1f1ffffff000000000000010101000000 +fffffffdfdfdf9f9f90606060000000b0b0bfefefe000000030303000000010101ffffff +f6f6f6fbfbfbfffffff8f8f8ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001ec90435d81d61f41f58bfdde6ff +f4ebe2ecefdee9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff2ebdbf1e5cff7ead7f4f0e7e3e8eee2f2ffd8f4ff224680244f940c3b89 +154597123f90042d7c0b3077001e61213b7831457a4e5c83545d7c7b829e6d758a606777 +757c84909598d1d6d2f2f3ede4e4dae4e1d8f3efe6faf3edf1e8e3efe4e2f6ede8f1eae0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfedebdff0eee2efede0edebdeeff0e2 +e9ebdeedeee6959a96f8ffffeffbff2939530e22479bb1e2122c670b286a98bff889c2df +2e748011616c38919937949b27818a206f7e1f607413405f7e9cc2435a845a709fd4f3ff +ddffffd6ffff225d952762c03065c3426fa83b6595ccfdff4179ce205bc32e68cc3361af +4068aedbffff3f65b63b5fb3526fab4b5763fefff8fffffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf7faef +94978ecdccd2f9f6fffffafefffff1ffffda070700ebeca68a8d4a040600feffe0f9f9ed +fffffdfeffff848587010101fffffffdfdfd000000f4f4f4ffffff000000fffffff6f6f6 +0a0a0afefefeffffffffffffebebebffffff0e0e0ef0f0f0222222f6f6f6000000ffffff +ffffff070707fefefef0f0f0ffffff050505e7e7e7040404fdfdfdffffffffffff000000 +ffffff000000ffffffffffffedededffffff080808fffffffffffff7f7f7080808ffffff +fffffffefefefdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001ec90435d81d61f41f58bfdde6fff4ebe2 +ecefdee9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff2ebd9f5eaccfdf2d4f6f1dddee1d8deebf1d2e9fb4b688821446c0b315e062f5d +1036632346704664884e69866d839b62748a5c667f80889dd0d7e9edf3ffedf4fcecf2f2 +dfe4defbfef5eceee1f1f2e2f3f1e2eeebdceee8dcf1ebdff6ede4f5ece3f1ebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfedebdff0eee2efede0edebdeefefe3e9ebe0 +edeee6959a96f1fafff2feff2e3e5798accf253b6a97b0e80e2a6983ace024667e479aa2 +38929d2585930c6f8217758f06567b0f4e7a133e753a57936072b0e3f6ff5871a9355787 +3d6a94d2ffff3773cb326bc2336296d9ffff4b81bf1d58a83979da2867c43e70b7cdfaff +3965ac416db63f6bb645689e98aab4f1f9eefefffdffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfcfef98c8e8d +bbbac0fffdfffaf5f9fffff4787554f6f6c48283498b8c530c0d0079795dfffff6fbfbfb +feffff83838b000002fcfcfcf6f6f6000000ffffffffffff000000fcfcfcffffff000000 +fafafaffffff000000050505000000000000fafafa000000000000ffffffecececffffff +0000000000000b0b0b000000000000ffffff050505fefefefffffffdfdfd050505ffffff +070707060606f0f0f0fffffff7f7f7000000fffffff8f8f8fbfbfb070707f7f7f7f6f6f6 +fffffffcfcfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefde +e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f2ebd9f3e8caf8edcdf4eed4e5e6d4eff6efeefcffb6cad589a3b2658093668395708c9a +647f8a5f777b738786cdded8f0fffcedf6ffe2e8f4eff3fceaeff3e8ecebe9eee7dcdfd4 +e6e9d8dddeccecebd7f4f1def0eddaefe9d9f2ecdcf2eaddeae4d6efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfedebdff0eee2efede0edebdeefefe3e9ebe0ecefe6 +959a96f0f9fef5ffff1c2b420e214298adda243b6f1a346f325c8e60abc23b97a4218594 +086e8400506d2b8bb15eb0e05394ce00266a84a0e94a5ca6e5f6ff556aab5572ac335b8e +d5ffff2561b93774c7386a9fd4ffff235b982c6ab72f71cf2c6dc74379bfd0ffff4e7fc4 +3666ae2c5ca6436b9f415965f8fffbfcffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffeffff5b5c61d2d1d9 +fffefffffefff9f6edffffe8060300d7d6aadddeb2030500f7fadffffff6fdfdfff5f5ff +8d8c9a000004fffffffefefe191919f2f2f2f8f8f8121212f5f5f5fbfbfb0b0b0bffffff +050505ffffffebebebffffff040404ffffff070707fefefe000000fcfcfcf8f8f80c0c0c +f9f9f9fffffffcfcfcffffffffffff000000efefeffffffff6f6f6000000f7f7f7ffffff +f1f1f10000000b0b0bffffff000000fffffff9f9f9ffffff000000fbfbfbffffffeaeaea +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eeda +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ecd9 +f4eacff3eacdf3ecd2efedd8f2f3e5eff5ebf2fbf6dfeae6eefaf8d9e8e3d9e6dddceadb +e7f4e0e2efd5f7ffe4dce4cde2e7e1e1e2e4ecececebece7ebede2edefe1e9ead8f2f1dc +f8f8e0f7f5dcf3f1d8f0eed7f0ebd7f0ebd7f1ecd9f2ecdcefecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfedebdff0eee2efede0edebdeefefe3e9ebe0ecefe8949a98 +f5fdfff5ffff27364b2c3d5b1f325c001647233a701b45751263810d738900627a005976 +319ebf52b5df348abd094b880c3b815f7cc8485ba8e7f7ff485ca5465ea4486aaad2feff +2a65bf3674c9ceffff4271a53e75b83976c72466c62a6bc7c4faff3566a92557a03a6bb7 +4071be4973ad86a1b6e6f4f5fcffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffefff9f9ff92929ed5d4dcf4f4f6 +eeeae7fcf9f0fffff1ffffec040300040300ffffe4ffffe9fffff4fffffffefdff868499 +000005fffffff5f5f5000000fffffff9f9f9000000ffffffffffff000000ffffff000000 +fffffffffffff6f6f6000000f0f0f0000000ffffffffffff000000ffffff000000ffffff +f6f6f6f0f0f0000000f8f8f8050505fdfdfdffffffffffff070707fffffffbfbfbfafafa +ffffff000000f2f2f2101010fafafafffffff7f7f7060606fffffff9f9f9fffffff6f6f6 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf6efdc +f2ead7f3ecdaf4eedee7e3d7dedacfebe9dde8e8dceeeee2ecedddeff1dcedefd7f2f5d8 +e1e5c2f2f6d1e2e5c6f6f7e9f2f1ecf1eee7edebdfeceadbedecd8f0efdaf5f3daf0eed5 +e8e7cbe6e5c9ecead1f3eed8f2edd9f3eedaf6f1deefecddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfedebdff0eee2efede0edebdeefefe3e9ebe0ecefe8949a98f9ffff +dce6f0f3fffff1ffffddefff1d325d2c417083aedb4ea3c80067881184a336acca33a6c5 +03709117749d1f6d9b0032685e8ac74263a64663a9e2ffffd8faffd0f8ff4677c63974d0 +356ec7d8ffff426faa2759a22c64b93877d82a66c6d2ffff4d7cc44272be2a5baa3e6fbe +3962a2617a99f0fcfffcffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffefffdfcff858494b5b4bafffffdfffff8 +fffff6fffcf5f8f5ecfffff3ffffeffafae2ffffecf6f8ebf3f3f5fefcff7d7b91000007 +fbfbfbffffff000000fcfcfcffffff0e0e0efffffffdfdfd030303ffffffffffff080808 +000000000000000000ffffff060606f7f7f7ffffffffffff000000efefef0404040e0e0e +020202fffffffdfdfd0000000d0d0d000000000000f5f5f5ffffff000000101010000000 +ffffffffffff000000000000080808000000fffffffdfdfdfffffff4f4f4ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0ebe6e0ece7e3 +efeae6f8f0edf0e6e4f5ece7f9eee8fdf3eaebe1d7f7ede1f8efdef1ead7fbf5dfe7e3c8 +f5f4d6f4f2d9efe9dbefe8deebe5d9f1ebddf4f1e0f2f0dbedebd4e5e1c8f2eed5f3efd6 +f3f1d8f5f3dcf5f3def2efdcedead7e9e6d5efecddefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeeadef1ede1efede1edebdfefefe5e9eae2eceee9949a98f9fffff7ffff +f4ffffe8f7fff1ffff1b2d518092ba6c97c23693bf36add72ca8ca0d8aa60a8799148c9a +2694a13595a5004b623274944d86b134679c3669aa4175be245dac2f68bf235bba3b6ec7 +365ca34d70b4355ead4476cd2f66ca376dcd3966b9385fae3861b3426cc0325fb24c71b7 +7487b2f7fffffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffefff9f6ff87849587878986877f7e7f718c8c80 +8c8b897f7d7e7c787787877d9799847779638689788f8f8d79768b938fa603020af8f8f8 +f0f0f0fffffffbfbfbffffffebebebfefefef8f8f8ffffffedededffffffffffffeaeaea +ffffffffffffeeeeeeffffffe8e8e8fffffffffffff8f8f8fffffffffffffdfdfdededed +f4f4f4ffffff000000fffffff1f1f1ffffffffffffeeeeeefffffffefefef6f6f6fdfdfd +ffffff050505fffffffffffffffffffbfbfbf7f7f7fefefefffffff6f6f6ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeebe2ecececececeee9e7ea +eee8eae9dfe0fbf0eeeee0ddeedfd8f7e6deffeee4f0e2d7e9ddd1fff9eaefe8d8f5efdf +f2ecdceee6dbf6eee3f3ebe0f3ebdeefe8d8ece7d4f7f2def7f2dcede8d2f4efdbf2f0db +e9e6d3e8e5d4f1eeddf4f1e2f0eddeefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeeadef1ede1efede1ebebdfefefe5e8ebe2eceee9949a98f9fffff2fbfff5ffff +f0fdffe6f4ff2433508493b4395c822a72a43392c23799c02c8fac086c7b2b8c923f9999 +40908f0042487ab2c1336580426f993b659f3a65aa406ebc3666ba3a6cc13f6ab9415ea0 +4e67a94969b23b64b43463bd3a68c04266b44565ae4a6cb63d61ad4369b44160a06875a2 +f3f7fffefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffefffffcff00000c020300000200000300080a00010000 +0403090502090505030102001519020003000001000f0c1d000012000005ffffffffffff +fbfbfbfefefefffffffffffffffffffffffff9f9f9fffffff5f5f5ffffffffffffffffff +f9f9f9fffffffbfbfbffffffefefeffffffff9f9f9fffffff9f9f9fbfbfbffffffffffff +fefefe020202f0f0f0fffffff7f7f7f4f4f4fffffff8f8f8f3f3f3fffffff4f4f4ffffff +000000fafafaffffffebebebfffffff9f9f9fffffffdfdfdfbfbfbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfecece4e2e6e7eaeff3edeef2eae8eb +e8e2e2f3e9e7fceeebefe0dbf8e7e0fbeae3f6e7e2fff1eeddd2d0fffcfaf3ebe9ede5e2 +f2e9e2ebe1d7fff7ede4dad0f8eee2fcf4e7ebe4d4f4edddeee8d8f2ecdcf2efe0f2eee2 +e5e1d5f6f2e7e3dfd6f3efe4f2eee2f4f0e4ede9dde3dfd3fcf8ece4e0d4fbf7ebefebdf +f4f0e4ebe7dbebe7dbf2eee2f0ece0eae6daf4f0e4ebe7dbefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeeadef1ede1efede1ebebdfefefe5e8ebe4eceee9949a98f9fffff8fffff1fbfff5ffff +f5ffff1b273d25314b1a2a4c122c5f14336a1436631a3e60052b401b414c0f3133203c3d +1d303653616e585f796c7199545990494e905a62ab4b5da73f60a5486aa74e5f934a5a8d +5167a14f6dad385da34b6eb2445e9b4f659e46609945629a3d5e944b6393989cc1fffbff +fffefffffffffffffffffffffffffffffffffffffffffffffffffff2f2f2ffffffffffff +f9f9f9fffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffefffdfafffffdfff4f5edffffedf9fde6f2f6e5fffffffcfcff +fffdfff2f3f5fffff4fcffeaf7fae7fffff8fefcfffffdfffffeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fafafafffffffafafaffffffffffffedededfffffffafafaffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffafafafffffffafafaffffff +ffffffedededfffffffafafafffffff3f3f3fffffffffffff0f0f0fffffff5f5f5ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc8 +0030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfecece2ebf1ede1eae700030004050016130c +060000ddd3cafff2e9f6e5ddfeefe8eedfdae8dddbfffbfaddd4d7e6e0e4f1ebedf4ebe6 +f0e6ddebe1d8fdf3eaece2d9070000eee6dbfff9eee5dfd3fffdf3e8e4dbf8f4ebeee9e3 +f1ece6efeae6f5f0eae7e3d8efebdfeeeadefcf8ecefebdfe8e4d8f2eee2e4e0d4eeeade +ece8dcf5f1e5f5f1e5ebe7dbeeeadef4f0e4ebe7dbefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeade +f1ede1efede1ebebe1efefe7e8ebe4eaefeb949a98f9ffffe4ebf1f8fffff2fcfff7ffff +f7fffff5fdfff7fefff8fcfff8fbffe2e8fff7fefff2fafff8fffff8fdfff8fbfffefdff +a4a2ad676477837e9c6a658da2a0cf5c5c908b93c44b648d8ca6c95962839da2c2536186 +8399c24a6793819cc753658b9dabce5d70917a91b16781a28296b1757389f8f0fdfffeff +fffffffffffffffffffffffffffffffffffffffffff6f6f6fefefef9f9f9fffffffefefe +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffefffffdfffffefffffff6f2f5e0feffecfefff1f8faf9fcfffffafaff +fefffffefffafefff3f7f9ebfffff6f8f7fcfaf9ffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +eaeaeafffffff7f7f7fffffffffffffcfcfcffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffeaeaeafffffff7f7f7ffffff +fffffffcfcfcfffffffefefefffffffffffffbfbfbffffffe1e1e1fffffffafafaffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d3 +2064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeceddfe7efe0f2fded000500e2e6d5e7e8d6e1decb +251e0beee6d3f2e6d6f4ebdcf8eee4f1eae2e9e4e0fefaf7eeecedf3efeef6eeebe6ddd6 +f6ede6ece3dcfffbf4070000fffaf5d6cfc9fdf6f0f4ede7ece7e3040000efeae6f6f1ed +f4efece6e1ddfdf9eee5e1d5ece8dcefebdfdfdbcff6f2e6f8f4e8f3efe3f9f5e9e9e5d9 +ede9ddf5f1e5ece8dcf0ece0eeeadef0ece0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeebdcf1ede1 +efede1ebebe1efefe7e8ebe4eaefeb949a9af9ffffebf3f6f9fffff3fcffedf6fff8ffff +f9ffffeff5ffe1eaf3f7fffff8ffffecf5fcf8fffff8fffff9fffff8fffff8ffffeef8ff +ecf9fff4fffff0fffff1ffffe3f6ffeeffffedfffff0ffffe7eaf1fffeffeaf0fcf4ffff +eeffffebfefff2fcfff9ffffeaf7ffe3f6faeeffffeffefff0ecedfffcfbfffefdffffff +fffffffffffffffffffffffffffffffffffffffffffffffff9f9f9f8f8f8fffffff3f3f3 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcfff3f1f48d8f84888b78797e6a858b7d797d7c83888e8d8f9b7f828b +797d7e7f817cbbbcb4e4e5ddfffffdfffeffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffff +f7f7f7f8f8f8fffffff2f2f2fffffffbfbfbffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffefefefffffff7f7f7f8f8f8fffffff2f2f2 +fffffffbfbfbfffffff8f8f8fcfcfcfffffff9f9f9fffffff1f1f1ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f7 +1851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeceddde6ebd7dde5ce0b1000eaeed7f9f9e1fefce5dad6bd +080200f2ebd8f0e9d7f1ebddf0ece1f0ede4dfded9e4e3dfebeae6f1ece8fff9f3ede6e0 +f0e9e3ece5df060000e6dedbfffdfae2dad7ede5e2f4efec110c09e8e3e0ede8e5dfdad7 +f4efebece8ddf9f5e9f0ece0f0ece0fffff3ede9ddede9dde4e0d4f2eee2e1ddd1ddd9cd +f3efe3f2eee2f2eee2e5e1d5f0ece0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeebdcf1eedfefede1 +ebebe1eeefe7e8eae5eaefeb949a9ae7eff1f9fffff7fffff9fffff2f7fdfbfffff7faff +fbfffff9fffbf1fdf1f0faf2f9fffff7fcffeef3f9f2f6fff9fffff6fffff4fffff0ffff +e8fdfeeeffffdff8f2edfffdddf7eae4fbebf7fff8fffff8fffdfafffffdf9ffffebfaf7 +f5fffffefffdfcfdf7fbfffaf7fff8ecfff2f8fff8fffdf4fffcf6fffefbffffffffffff +fffffffffffffffffffffffffffffffdfdfdfffffffcfcfcfffffffffffffffffffefefe +f4f4f4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffefffffeff8b8c84dfe2d7d5d8cddde2dbf8fefcdadfe5dce0ecdde0efe8eaf7 +d5d8e197969b5d5d5bfffffafffffafffffdffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedededfefefe +fefefeeeeeeefffffffffffff8f8f8ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffedededfefefefefefeeeeeeeffffffffffff +f8f8f8f2f2f2fffffffffffffafafafdfdfdefefeff8f8f8fafafaffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecddffffede6e8d2050500e5e5cdf4f2dbedebd4f3f1da060100 +f6f1ddf2efdcefecdd0d0b00030100010100fffff6dadad2f4f1ea040000040000f6f1eb +f1ece80c0703eae5e1f0ebe70d0804fffefaece7e304000017120eddd8d4efeae60c0701 +040000040000f7f3e7e7e3d7040000040000040000070300e8e4d8fffff3faf6eaf2eee2 +e3dfd3ebe7dbe8e4d8f4f0e4efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0eadcf1eedfefede1ebebe1 +eeefe7e8eae5eaefeb949a9af9fffff9fffffbffff0001040c10110001020000020c110b +00040000050012180af8fbf4fafafcfffdfffffdfffefdfff9fdfff5fefff5fffff4ffff +f1fffcf2fffaecfeeef4fff3f5fff1f7ffedfffdf4fff2ecfffaf7fefffaf5fff6f9fff8 +fffff8fffff6f7fbedf8fff2edfeebfbfff3fff5effff8f5fffdfdffffffffffffffffff +fffffffffffffffffffffffffffffff3f3f3fefefef8f8f8fafafafdfdfdffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +f7f5f6eeeced8a8a8af7f9f8fefffffafefffbffffeff6fef5fbfffbfdffe5e5fffcfcff +9d9aabf2f1f745453dfffff6fffffbffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffff9f9f9 +fffffffffffff0f0f0ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffefefefffffffffffff9f9f9fffffffffffff0f0f0ffffff +fffffffffffffafafaf9f9f9fffffffffffffffffffcfcfcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecdde8e2d2e9e2d20b0500f4eedeebe5d5eae4d4ece9d8050200efecdd +e8e6d9030100f9f7ebdbdbcfedede1020200edede3030000f6f6eef1eee7030000e7e4dd +060300ece9e4040000eae5e1dbd6d0e5e0da130e08eae5dffcf7f1040000ece8dff7f3e8 +f1ede1090500f2eee2040000f4f0e4efebdff7f3e7070300c9c5b9ece8dcf6f2e6f2eee2 +fdf9edf2eee2dedaceefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff0eadcf1eedff0ece0ebebe1eeefe7 +e6ebe5eaeeed949a9af3fcfbf9fffff4fafa000100feffffdadad8fffffbbfc0baf9fff1 +c6cdbd777a6f060500fbf5f7fffcfffffcfff5f2fbfefefffbfffff5fdfff4fefde9f4ee +f5fff7f9fff6f9fff4f8fff1f3faeafffbf8fff9fbfff6f7fffffdfbfffbfcfffafffefa +fdf8f4fcfdf5f8fff3f7fff6fbfff8fffbfdfff5fbfffdffffffffffffffffffffffffff +fffffffffffffffffff6f6f6fffffffffffffffffffffffff4f4f4fafafaffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd +fffeff807f85fefeffeceff8fbffffdfe6ecf9fffff9fefff1f5fffbfafff8f6ffa9a6c3 +54525f55544f58584cfffffbffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffafafaf3f3f3fafafafefefeffffff +f6f6f6f3f3f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffafafaf3f3f3fafafafefefefffffff6f6f6f3f3f3ffffffffffff +f3f3f3f1f1f1fffffff7f7f7f5f5f5fdfdfdffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff1eae0f5e8e2f4e5e20a0000fff8f4e7dcd8fffdf8e9e2dc0b0600f5f2ede8e5e0 +0300000505000c090215120b030000f0ede4ddddd3080a00e1e1d7f5f5ebedede3010100 +0c0c04f0ede4eeebe4fffcf3f0ece3110d04dbd7ccf2eee3191208e3dcd2eeeadef8f4e8 +040000e0dcd0171307dcd8ccf9f5e9e2ded20c0800fffcf0f7f3e7e9e5d9e1ddd1eae6da +fbf7ebf8f4e8efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff0eadcf1eedff0ece0ebebe1eeefe9e6ebe5 +eaeeed949a9afbffffedf3f3fcffff000100c3c5c0f4f5efc3c3bbfefff9c4c9c5fbffff +7c7c7ccdc9c8060000fffcfdf5ebecfffcfdfffefdfffffdf0f2f1fcfffffeffffffffff +f8f6f9fcfcfcf3fdf5fefffdfeecfafff6fffff3fff8f2fefcfffff8fbfffff9fffffbff +fffdfffbfffff4fffffbfffffff0fffff6fffffcffffffffffffffffffffffffffffffff +ffffffffffffffffffecececfdfdfd050505f0f0f0171717fdfdfdfdfdfdffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f2f0fffeff +6d6b78fefdff8f90a48588979097a1727a85787e947376999c9acc7571a478739b08051a +c5c4bf545547fffffbffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffefefe0f0f0fffffffffffffdcdcdcffffff +fffffff9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffefefe0f0f0fffffffffffffdcdcdcfffffffffffff9f9f9f0f0f0ffffff +fffffffffffff3f3f3151515fefefef0f0f0ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001dc8002fd32064f71a51b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f5e8dff5e9dbefebdfeceddfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f1eae0f0e2dffff5f50a0000e4d9d7f8ececf1e7e5efe7e5040000eae6e3f3f0eb040100 +f2efeae4e1dae9e6dff5f1e8f1eee5edede1f7f7eb010100e0e0d4f7f7ed060600dbd8cf +0c0a00eeebe2f2f0e4e9e5da040000fefaeeddd9cd0d0700f1ebdfece8dcefebdf0a0600 +e9e5d9070300f7f3e7e6e2d6f9f5e9040000f9f5e9e4e0d4f4f0e4fbf7ebe5e1d5efebdf +f2eee2efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfedebdcf0eedfefede1ebebe1edefeae6ebe7e7f0ef +919b9cf7fffffcfffff6f4f7040000fffdfbcac5c1fffff8c5c8c1fcffffc1c5c6888687 +8f8b8a8f8785070000fffcfafbf3f0fffaf6fcf8f5fffffdf3f3f301000209060d030007 +fffdfffcffff0000050e00110a000e08000d060210fefeff00000904000b04000b05020d +000007f8fffff5f7fffff8fffff8fffffcffffffffffffffffffffffffffffffffffffff +fffffff4f4f6fffffff3f3f5000002ffffff000002f2f2f4fffffffffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfcfef9feffff878392 +fffbff807a960d0723c6c4dc14142e080b2c181b4602053c06073d1b1a46010019fffeff +54544cfffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000fffffff6f6f4fffffffbfbf9fbfbfb +fffffdfffffffffffdfffffffffffdfffffffffffdffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000002fffffff6f6f8fffffffbfbfdfbfbfdfffffffffffffffffff4f4f6 +fffffff6f6f8000002ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001cc80433d71c60f32057bedee7fff4ebe2edf0dfeaefdb +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeeecdfebeddfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f7f0e6eee5dc060000fffaf0f3ece4e9e2d80e0a01e6e2d7f7f3eae4e0d5050100e5e1d6 +faf6ebeae6db090500e3dfd4030100fefcefe2e0d3030100ebe9dd030100eeeadfefebdf +040000f8f4e8e8e4d8040000e5e1d5fffff3040000ede9ddf1ede1e9e5d9040000f6f2e6 +040000ede9ddf1ede1ece8dc0a0600dedacefaf6eae9e5d9f7f3e7e8e4d8f9f5e9eae6da +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecdfeaecdeecf0e1eceee3e9ece3ebf0ece3ece9e2f2f18b9d9d +f7ffffe9eaeffff9ff120002d7b9c1fff9fbc9ccc5f7fff6c0c3bafffff8d1cec7fbf6f2 +c7c2be060000fffdfbf9f3f3fffefdf6f2f3fffeff010002fffefffcfbfffcfbff040309 +f9fafefffefffffcfffbf5fffffdff000005fcfbfffffefffffefffffdfffaf9ff010207 +fcfffff9f9fffffbfffffbfffaf7fffffeffebeaeffffefff5f4f9fffefff6f5fafffeff +faf9fefefdfffffeff000004fffeff000004fffefffffffff8f8f6fffffbf1f1effefffa +fffffdf6f7f2fffffdf7f8f3fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfefffbf9fffbfbffff86838cfff7ff +8b73971e04311500301e10450502390f144c000a40041040070f3600001bfffcff534d57 +fdfafffffefff9f8fdfaf9fefffefff0eff4f9f8fdfffefff9f8fdfffefffffefffbfaff +f6f5fafffeffefeef3fffffffffffd060702fafaf8fffffbf9f9f7fffffbf4f4f2fffffb +fffffdf8f9f4fffffdfbfcf7fffffdfafbf6fffffdf0f0eef8f8fafffefffdfcfffffeff +fcfbfff9f8fdfffefffaf9fefffeffeeedf2fffefffffefff3f2f7fffefffffefffcfbff +faf9fe030207fffefffefdfffffefff1f0f5faf9fefffefffdfcfffffefffcfbfffcfbff +fffeff08070ce5e4e9fffefffffefff2f1f6fffefffefdfff8f7fcfffeffecebf0fffeff +fffefffffefffffefffffefffffefffffefffffefffffefffcfcfefdfdfffefefefdfdfd +fcfcfcfffffff9f9f7fffffdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001cc80433d71d5ff32057bee0e6fff4ebe2eeefdfeaefdbeeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0ece0 +f7f3e7040000040000040000070300f5f1e5e8e4d8f4f0e4eeeadefbf7eb0d0900040000 +0b0700eae6dafffff3f7f3e70400001a160aece8dcf6f2e60d0900e3dfd3efebdff4f0e4 +090500e5e1d5ece8dc181408c7c3b7fffcf00c0800040000130f03dedacef4f0e4040000 +0400000a0600060200e4e0d4fffff3e6e2d6efebdff9f5e9dcd8ccefebdff4f0e4efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecdfeaecdeecf0e1ebeee3e7ece5eaf0ece1ede9e0f3f18a9e9df5ffff +fffefffff7ff170004fff4ffd1bec0eef5eebccabdfefff6cbc8bff3f0e9e1ded9fffefa +030000faf4f4fffefdfffcfdfffdfffffeff010004fffefff8f7fcfeffff000004fffeff +f6f5fafffeffffffff000002fffffff1f1f1fefefef9f9f9fefeff050507f8f7fcfdfcff +fcfbfffffdfff9f7fffffeff0000040f0e14010005111016fffefffffefff2f1f608070d +06050a000005000004fffeff000004000005000002070707eaebe6fffffdf4f5f0fffffd +fffffbf5f5f3fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfcfffff7fffff1fbfd858086fff8ffa2869c +fff2fffff2fffeebfffcf6ffeef3ffeefcffe6f6ffe7f0ff050922efecf74d474bfefcff +faf9fefffeff0302070000050a090efffeff000004030208fffefff4f3f9fdfcff0a090f +050409000005f7f7f9f0f0f0000100fffffdf2f3ee0e0e0cf7f8f3fffffd000100010100 +000100fffffdfffffb000000000100000000171715fffefff9f8fdfcfbff020106000005 +07060bfffeff03020703020808070c000005f0eff4fbfafff8f7fcfefdfffefdfffffeff +00000403020807060b000005fffefffaf9fff9f8fd0000050c0b10000005fefdfffffeff +07060bfffefffbfaff000005fffefffdfcfffffefffffeffecebf0fffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffffffbfbfdfffffff0f0f0fdfdfd +fafafafffffdf2f2f0fffffffffffffffffffffffffffffffffffffffeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001cc80433d71d5ff32057bee0e6fff4ebe2eeefdfeaefdbeeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfe6e2d6e6e2d6 +f7f3e7fdf9eddcd8ccf4f0e4f1ede1efebdfe7e3d7f3efe3e8e4d8e6e2d6f2eee2f7f3e7 +e6e2d6e3dfd3ece8dcefebdfe5e1d5f1ede1e1ddd1e8e4d8fffff3ebe7dbeae6dae8e4d8 +fffbefeae6dae7e3d7fffcf0ebe7dbe2ded2ede9ddeae6daf8f4e8eeeade1c180cece8dc +e4e0d4f7f3e7f5f1e5e7e3d7e2ded2f7f3e7f5f1e5ece8dcf5f1e5e3dfd3efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff0eadcf1ede1eceee3e7ede3e8f2eae1ede9e0f3f18d9d9cebf6f8feffff +fffbff817078cfc0c5fffefbc2cdc5f5fffac2c4bffffffbd1d0ceefeeecccc8c7060503 +fffdfcf2f1effffffdf9f7f8fcfafbfffeff000004000004000004fffefffdfcfffffeff +fcfbfff2f2f4161616f9f9f7fdfdfbfffffdfffffdffffff040404e1e1e3fffefffffeff +f8f7fdfffefff8f7fc0e0e10f9f8fdfafafcfbfaff000002f3f2f7121214fffefff2f2f4 +fffeff000002f0eff4000002fffeffffffffffffff000000f9f9f9fffffdf2f2f2f4f4f2 +fffffff8f8f6fdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfb +fdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfb +fdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfdfdfb +fdfdfdfdfdfbfdfdfdfdfdfbfdfdfdfafdfff4fcfff8ffff7f7d80fdf0e7978271fff4ea +e5d0d72f203feee8fff5f7ff0b1364f0faffd2dbff0d1321ffffef55553dfffffaffffff +f7f6fb050507fffeffffffff000004fffffffffeff000002fffefffafafcf5f4f9ffffff +fffeff060608ffffff000000ffffff000000f7f7f7fffffd000000fffffdf6f6f6fffffd +000000ececea0d0d0dfffffdedededf2f2f2000002ffffff020106ffffffefeef3ffffff +fdfcff000002faf9fefffffffdfcff0c0c0efffefff9f9fbfffefffffffffaf9fe000002 +fffefffffffffefdff020204fdfcfffffffffffefff7f7f9fffeff070709fdfcff000002 +fffeff000002fffefffffffff6f5fafdfdfff3f2f7fffffffffefff8f8fafdfcfffdfdff +fdfcfffdfdfffdfcfffdfdfffdfcfffdfdfff3f3f5f9f9f9fffffffffffffffffdf9f9f7 +fffffdfffffdfffffffffffffffffffffffffffffffffffffffeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001cc80433d71d5ff32057bee0e6fff4ebe2eeefdfeaefdbeeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff5f1e5fffcf0eae6da +e0dcd0f6f2e6eeeadee8e4d8f7f3e7f0ece0f8f4e8eeeadeeae6daf2eee2f6f2e6f0ece0 +f8f4e8e8e4d8fcf8ecfaf6eaf4f0e4e6e2d6efebdfdedacef2eee2eae6daf0ece0e6e2d6 +eeeadef4f0e4ece8dcf1ede1f8f4e8f3efe3ede9ddf5f1e5ebe7db040000ece8dce4e0d4 +ebe7dbe7e3d7e7e3d7f8f4e8f0ece0e1ddd1f3efe3faf6eae8e4d8efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f1ebdff2e8dcf4ecdfefede1e9ece1e8f2eae1eee7e2f2ef8e9c9cf8fffffcfffffffeff +908c8dfffffdb8bfb8f5fffabacac0f9fdfec1c0c5fffeffbdbdbffffdfe050505f8f7f5 +fffffdf3f2f0fffffdfcfbf9010000fffffff7f6fbfbfaff000004f3f3f5fffffff0f0f2 +020202fffffdfffffbfdfef9f9faf4fffffb000100fffffdfffffdf4f4f6f5f5f7fffeff +ffffffffffff000000fffffffefefeffffff070707f8f8f8000000fffffff6f6f6ffffff +000000efefef090909fffffff3f3f3fcfcfc000000fdfdfdfffffffffffffffffffafafa +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcfffff7ffffecf4ff8d8c88fffeed817056fffbe646332d +504452fef9ff080a43aab4f2131e54e2ebff000508ffffe95a5b3cfefef4f3f3f3ffffff +000000fffffffefefe000000ffffffffffff090909f0f0f0ffffff030303000000060606 +000000ffffff000000030303f7f7f7fcfcfcffffff000000000000050505000000070707 +fafafa010101fffffffcfcfcffffff000000fafafa050505000000fbfbfbffffffececec +111111fffffff8f8f8ffffff000000fcfcfcfcfcfcf5f5f5ffffffffffff020202fbfbfb +f4f4f4ffffff000000ffffffffffff000000020202000000000000f5f5f50d0d0d000000 +fffffff6f6f6f8f8f8fffffffffffffcfcfcfffffffdfdfdfefefeffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffde9e9e9fcfcfafffffdfffffdfefefc +fffffdfffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001cc80433d71d5ff32057bee0e6fff4ebe2eeefdfeaefdbeeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfece8dcdedacefffff3e8e4d8 +f4f0e4eae6daf4f0e4ebe7dbf8f4e8e2ded2eeeadefffef2eae6dae4e0d4ece8dceae6da +f3efe3e0dcd0d7d3c7efebdffffff3f0ece0dedacefdf9edfcf8ecf1ede1e8e4d8ede9dd +efebdfeae6daeae6dae8e4d8dfdbcffffff3e1ddd1f4f0e4ece8dce4e0d4fffff3f1ede1 +fffcf0eeeadeefebdfede9ddf2eee2f1ede1e4e0d4f3efe3efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdd +f4e8daf7ebddf2ece0ebebdfeaf1e9e1eee5e3f2ed909c9af9ffffeff3f6f4f5f7fcffff +88938df2fff86c807481928ac1c6ccfefeffc0bec9f9f9ff929196fefffff1f1f1f7f9f6 +fffffbfffffbfbfcf7000000f6f4f5fffefffffeff010002fffffff2f2f0fffffd13140f +eeefe9f7f8f0fffff8fffff8fffff8050600fdfef8f0f1ebfffffdfffffdfffffff7f7f5 +fbfbf9080904fffffbf3f4effffffb000100fafbf6070803f4f5f0fffffbfffffb000100 +fffffb000100ecede8fffffbfdfdfd171717ffffffefefefffffffffffffecececffffff +fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc +fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc +fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc +fcfcfcfcfcfcfcfcfcf9fefaf8fffaeffaec7b7b6ffffdf494817bfff7f6feebef2c2129 +ededf7f8ffff36444d485a5edce8e8000300fffff6525044f8f7f2fffffbf1f2ed020300 +fffffbedeee9000100fffffbf2f3ee070803fffffb000100fffffbfffffbfafbf6080904 +f2f2f2020202ffffff000000ffffffffffff000000fffffffffffff3f3f3fffffffafafa +000000fdfdfdfffffff5f5f30b0b09fffffbfefffafffffb040500000100f8f9f4000100 +fffffbf7f8f3fffffb000100f5f6f1fffffbfffffbf9faf5fdfef9000100fffffbfffffb +f4f5f010110cf6f7f2060702fbfcf7fffffbf5f6f1010200fffffb0c0d08fffffb000100 +fffffbfffffbf3f4eff7f8f3fdfef9fffffbf0f1ecfffffbfcfdf8fcfdf8fcfdf8fcfdf8 +fcfdf8fcfdf8fcfdf8fcfdf8f7f8f3fffffbf8f8f6fffffdfffffdfffffdf1f1f1ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc8 +0433d71d5ff32057bee0e6fff4ebe2eeefdfeaefdbeeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff5f1e5ede9dddfdbcffffff3e9e5d9 +e9e5d9f2eee2f2eee2e8e4d8fcf8ecf9f5e9d8d4c8ede9ddf4f0e4fdf9edf9f5e9ebe7db +fcf8ecfefaeef9f5e9e3dfd3ede9ddfdf9ede7e3d7eeeadee8e4d8fffcf0fbf7ebe4e0d4 +ece8dcf6f2e6faf6eafdf9eddad6caf7f3e7ece8dcece8dcefebdfeae6dae1ddd1e5e1d5 +e6e2d6e7e3d7ede9ddfdf9edf1ede1ddd9cdf2eee2efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf1eada +f5ecdbf6eadef0e9dfedf0e7e3ede5e3f2eb8e9d98f4fafafcfffffeffffedf3f1f7fffd +75867cf4fffa85948dfbffffc0bfcff0effd9f9fa9e9eaeff5f9fafefffffefffdeaece7 +fefffbf4f5f0010200fffffdfefcfdebe9ec131114f3f2f0fffffb040500f6f7f1fbfcf4 +fffff6fffff6fefff3000200fdfff2fffff6fefff5fffffafffffa000100fffffafffffa +000100fffff8fffff8f6f7ef0a0b03f6f7ef060700fffff8fcfdf5fffff8000100f6f7ef +0f1008fffff8fffffafffffb000000fffffdfffffdf7f7f5f6f6f4fffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfefff8f0fce6fbffed898a7afaf1ea9f8d8df2dee0f0e0e1f6eceadbddd2 +f9fff3daecd6c9dbc5f8fff3070f02fffff857544ffffff8eeefe7fefff7070800fdfef6 +fffff8000100fefff7fffff8000100fffff8010200edeee6fffff8fcfdf5000100fffffb +020200f3f3f1f8f8f6000000f1f1ef000000eeeeecf1f1effffffd000000fffffd010100 +fffffdfdfdfbfffffb000100fcfdf5fdfef6f3f4ecfffff8040500fffff8020300f8f9f1 +f6f7effffff8000100f4f5edfffff8000100fffff8fffff8000100f2f3ebecede5fffff8 +000100fffff8000100fffff8f6f7effbfcf414150dfafbf3000100f2f3ebfdfef6000100 +fffff8fffff8fafbf3fffff8eeefe7f8f9f1fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fbfcf6fffffafffffaf6f7f2f1f2edfffffdffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc80433d7 +1d5ff32057bee0e6fff4ebe2eeefdfeaefdbeeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff2eee2fefaeeeeeadedbd7cbeeeadef2eee2 +f3efe3e9e5d9efebdfefebdfede9ddfffff3e1ddd1f4f0e4e8e4d8e3dfd3ebe7dbefebdf +e9e5d9eeeadeeeeadee9e5d9f0ece0ece8dcf8f4e8e5e1d5f0ece0efebdfe6e2d6f2eee2 +f0ece0e1ddd1e0dcd0f8f4e8fcf8ecdedacef7f3e7ece8dcf4f0e4f7f3e7f0ece0fefaee +f6f2e6e9e5d9e6e2d6ebe7dbf3efe3f6f2e6efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddebedd8f3eedb +f9e9dcf7e6def4ede5e6ebe4e2f3eb8d9e98f9fffffffffff3eef2fffeffeff5f1f8fffb +f8fffaedf8f475798588899b818392f3f5fffcfffff2f7fafcfffffcfffdfcfffbf0f5ee +fefffbf6f7f20c0b09030102030002fcfafbfffffb010000010100040400040400060700 +010200070800010200010200030400020300050500010100010100090900070700010100 +0101000101000707000101000a0a000101000202000101000101000707000d0d01010100 +06060001010005050001010001010001010001010016160e050500010100010100010100 +010100010100010100010100010100010100010100010100010100010100010100010100 +010100010100010100010100010100010100010100010100010100010100010100010100 +010100010100010100010100010100010100010100010100010100010100010100010100 +010100000200020b000005000f10000700000b00001f0e040a00000b06000e1000000600 +000e00041200000600010800010200030100010100010100111105010100010100010100 +0404000101000a0a000101000202000101000202000303000d0d01040400040400010100 +01010014140c02020005050014140c010100020200010100010100010100010100010100 +0606000101001111070101000101001515090101000b0b00010100030300060600111105 +0101000505000c0c000101000101000404000a0a00010100101004030300010100030300 +0101000101000101001212060808000101000909000101000202000a0a00010100020200 +040400010100010100111105010100020200010100010100010100010100010100010100 +01010001010007090000010000010012130d080904e0e0deffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001cc80433d71d5ff3 +2057bee0e6fff4ebe2eeefdfeaefdbeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfebe7dbe8e4d8f0ece0f9f5e9f1ede1eeeadeebe7db +f9f5e9ebe7dbf5f1e5eae6dae8e4d8f1ede1f6f2e6ece8dcf2eee2f8f4e8e4e0d4fdf9ed +efebdfefebdfe8e4d8fffcf0e8e4d8e9e5d9f8f4e8efebdfebe7dbf7f3e7f2eee2eae6da +f8f4e8fbf7ebdbd7cbefebdff2eee2ece8dcf2eee2ede9ddeae6daf0ece0e9e5d9e5e1d5 +f5f1e5f2eee2efebdffcf8ece9e5d9efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddde4f0d8edf1dafde7da +fee3dcf9eae5e9eae4e0f4eb89a098f2fbfafffefffffafffbeef5fffefdf8faf5fdfffa +fcfffffefefffcfbfffefefff5f8fffbfefffbfffff9fffdf8fefafbfffafcfffbeff1ec +fefffbfffefcf2f1effffefff9f5f4f1f0ec0d0d05fffff5f3f3e7fffff3f4f5e5fffff1 +ffffefffffeff9fae8ffffeffffff1eeefe1fffff3fffff4f6f6eafcfdeffeffeffeffef +fbfcecfeffeffafbebfdfeeefffff1fffff1f5f6e6fffff1fbfcecf2f3e3fffff1fdfeee +fbfcecfefff1fdfef0fffff3fffff3fffff3f3f4e6f9faecfffff3fdfef0fdfef0fdfef0 +fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0 +fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0 +fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0fdfef0 +fcfef1f6fbf4f7fcf5fffff3fffce9ffffe6fef5d8ffffe3ffffe4fbfde5feffedfaffee +f1fde9fbffefeff4deffffecffffeafafbe9fffff1ebecdcfffff1fffff1fffff0feffef +feffeffbfcecfffff1fcfdedfffff1fffff0eeefdffffff0feffeff7f8eafffff3fffff2 +f3f4e6f7f8eafffff3eceddffffff3fafbedfffff3f7f8eafdfef0fafbedfffff3f9faec +fdfef0f3f4e6fffff1fcfdedfbfcecfffff1fbfcecfffff1fafbebf8f9e9f9faeafcfded +fffff1f5f6e6fffff1f4f5e5fffff1f4f5e5fffff1fafbebf9faeafffff1fffff0fafbeb +fffff1fdfeeef7f8e8f6f7e7fffff1feffeffbfcecfffff0f6f7e7f8f9e9fffff1f2f3e3 +fffff1feffeffdfeeefeffeffeffeffdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeee +fdfef0f4f6e9fffff6f9fbf0eeefe70d0e08fffffbfffffffdfdfdffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bc +e2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeaeeddddf4d7e6f4dafee6daffdfdc +ffe7e5ece9e4def5eb86a198e9f3f2fffcfffff7fffff7fffaebf0fffcfdfffdfdfffefd +fffefff8f7fcfffefffcfdfff6faf9fbfffefbfffdedf3effbfffdf0f5f1fefffdfefffd +fcfbf9fffffdfffefdf7f3f0fffffa010100fdfdf3fffff4f9faecfffff1fdfeecfdffea +ffffedffffeceff1dcfeffebf4f5e3ffffeffffff1f9faeafdfeecfdfeecfdfeecfdfeec +fdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdffea +fdffeafdffeafdffeafdffeafdffeafdffeafdffeafdffeafbfde8ffffedf2f4dfffffed +fdffeaffffecffffedf1f3defbfde8ffffecfeffebfcfee9f2f4dff4f6e1fcfee9ffffed +fdffeaf1f3defeffebffffedf9fbe6ffffedfeffebf2f4dff8fae5ffffedfcfee9ffffec +f9fbe6ffffedf9fbe6ffffedf6f8e3ffffedeaecd7ffffedffffecf7f9e4ffffedf6f8eb +f9fcfffbfcfffdfdf3fffee5ffffd7ffffd1ffffd3ffffdcfffee9fcfef1fbfdf8f9fef8 +f9fff3fbffeafdffe0fdffe0fdffe7fdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeec +f2f3e1feffedffffeff9fae8ffffeffeffedf1f2e0fdffeaffffedeff1dcfafce7ffffed +eff1dcfafce7ffffedfeffebfdffeafdffeafdffeafdffeafdffeafdffeafdffeafdffea +fdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeec +fdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeec +fdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeec +fdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeecfdfeec +fffff1f1f3e5fffff4fffff6000100fffffbfcfcfcfffffffffffffffefffffefffffeff +fefefffefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8ff +f4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfe8efddd9f6d7e3f6daffe5dcffdedcffe6e5 +ede8e4def5eb84a29af9ffffe6dce4fff2ffffeffcfffafffffbfff9edf1fffbfbfffbf5 +fffff6f7f7effffffafefffafcfffbe9eeeafbfffdf9fffdfbfffffefffff9fbfaf7f6f4 +faf9f7fffdfdfffefbfffff8010100fdfdf1fffff3f9faeaffffeffdffeafdffe9f1f3dd +f6f8e0ffffecfdffe9fbfde7ffffedffffedf7f9e4fdffeafdffe9fdffeafdffe9fdffea +fdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffe7 +fdffe5fdffe5fdffe5fdffe5fdffe5fdffe5fdffe5ffffe8ffffe8fdffe5fdffe5feffe6 +eef1d6ffffe8ffffe8ffffe8f1f4d9f7fadfffffe8ffffe8ffffe7f8fbe0f0f3d8fbfee3 +ffffe8ffffe8f8fbe0f4f7dcf7fadfffffe8ffffe8ffffe8f8fbe0f1f4d9ffffe8ffffe8 +fbfee3f3f6dbffffe8ffffe8f9fce1ffffe8ffffe7f4f7dcffffe8e7eacffffff0fbfcfe +fbfcfffdfdf3ffffe7ffffdaffffd5ffffd7ffffdcfffee7fffdeefdfdf5fcfdf5fcfef1 +fcffeafcffe3fdffe1fdffe7fdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9ffffed +ffffecf7f9e4f4f6e0f8fae5ffffecffffedfbfde7f7f9e1ffffe8f5f8ddf7fadfedf0d5 +ffffe8e8ebd0f6f9defdffe5fdffe5fdffe5fdffe5fdffe5fdffe5fdffe5fdffe7fdffe9 +fdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffea +fdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffea +fdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffea +fdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffeafdffe9fdffeafdffeaffffef +f3f6e5fffff3fdfff4000100fffffbfbfbfbfffffffffefffffefffffefffffeffffffff +fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2 +e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfe8efddd8f7d8e2f6dafee6dcffdedeffe6e7ece8e5 +def5ed86a19cf6f9fefffafffeecfafff9fff6f1f8f9f4fafffaffffefeffffeecfffee4 +ffffeaffffedf3f4e6fffff8fbfffafcffffecf2f2fbfffff1f2f4fefffffffefffbfaf8 +fffaf7fffefafffff8030000fffdf1fffff3fbf9eaffffeffffeeafffee9ffffeaf7f7dd +ffffeaffffe8f6f6defbfae5faf9e4ffffecfffee9ffffe7fffee9ffffe7fffee9ffffe7 +fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3fefee2f1f1d5ffffe6f3f3d7fdfde1ffffe6 +f2f2d6ffffe6fcfce0ffffe6fafadeffffe5ededd1ffffe6ffffe6ffffe6f0f0d4ffffe6 +f2f2d6ffffe5ffffe6fafadefbfbdfffffe5ffffe6fdfde1ffffe6ededd1ffffe6fbfbdf +ffffe6e9e9cdfafadeffffe6f1f1d5ffffe6f7f7dbf7f7dbffffe6fcfee6fcffecfcfef0 +fdfdf1fffdf0fffdeefffdecfffde9fffee5fffee1ffffe0ffffe1ffffe3fdffe9fcffec +fcfef1fdfdf1fdffeaffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7ffffebfbfbe3 +faf9e4ffffeaffffebf2f2daffffecf0f0d8f8f8dcfafadeffffe6ffffe6ffffe6f2f2d6 +ffffe6ffffe6ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe7ffffe7 +fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7 +fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7 +fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7 +fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9fdffe9ffffedf6f9e6 +fffff3fafcef020300fcfdf8fefefefffffffefdfffffefffffefffffefffffffffefefe +fffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eada +ebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfe8efdddbf5d8e5f5dbfde6deffe0dff9eae7e8eae7def5ef +8a9e9dfffdfffffafffdf7fff9fefff0ffff0004050800041200000e00000e06000b0600 +060300040200fffff3fefffafcfffffcfffffcfffffafbfffcfdfffffefffdfcfafffbf7 +fffef8fffff8030000fffdf1fffff3fbf9eaffffedfffeeaffffe7fcfce4f7f7ddf2f2d8 +ffffe8fcfce4ffffeafbfae5fcfce4ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3efefd3ffffe6f6f6daffffe6fefee2fcfce0fefee2 +ffffe6f7f7dbffffe5f6f6daffffe6fbfbdfffffe6fcfce0f6f6daffffe6ffffe6fbfbdf +fdfde1ffffe4fcfce0fcfce0ffffe6f7f7dbfafadeffffe6ffffe6f6f6dafcfce0ffffe6 +ffffe6f8f8dcffffe6ffffe5ededd1fefee2fefee2ededd1ffffe3fdffe3fdffe7fdfeee +fdfdf1fdfdf5fffcf5fffcf0fffde9fffee1ffffdcffffdaffffdeffffe5fdfeecfcfdf5 +fcfdf5fdfeecffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffeafcfce4fcfce4 +ffffe8fdfde5fbfbe3ffffeaffffe8ffffe6ffffe6eaeacef9f9ddf0f0d4fafadeffffe6 +ebebcfffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe5ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7fdffe7feffeaf9fce7fffff1 +f9fbee060700f1f2edfafafafffffffdfcfffffefffffefffffffffffffffefefefffffd +fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dc +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfebeedde3f1daeaf2dbf9e8def8e5dfefeee9e1ede9e0f3f1909b9f +fff9fff7ecfcf2ffffe2ffffd9ffff001a14fffcfffff7f2f6e6b5fff4b2ffffc8ffffd4 +0a0700030200f3f4eefcfdfff6f9fff2f4fffefefffafaffeceaedfffffdfffefafffaf4 +fffff8030000fffdf1fffff3fbf9eaffffedfffeeaffffe7f7f7dfffffe8fbfbe1fefee4 +f3f3d9fdfde3ffffeaececd4ffffe7ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe8ffffe7f5f5dbf7f7ddfafae0ffffe8f7f7ddf9f9df +ffffe8f4f4dafdfde3fafae0ffffe8eaead0f8f8deffffe8f9f9dff5f5dbffffe8fbfbe1 +ebebd1ffffe8ffffe8fbfbe1ffffe8f9f9dffdfde3f5f5dbffffe7fcfce2ffffe7f4f4da +ffffe8f0f0d6ffffe8ffffe8f9f9dfffffe8ffffe8fefee4ffffe3fdffe5fdffe9fdfeec +fdfeeefdfeeefffdecfffde7fffde3fffee0fffee0fffee1fffee5fffeeafcfef0fcffee +fdffe9ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5fbfbe1ffffe8ffffe8ebebd1 +fbfbe1ffffe8f5f5dbf9f9dff9f9dfffffe8ffffe8ffffe7ffffe8f8f8deeeeed4ffffe8 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5fdffe7fdffe7fbffe8ffffeff7f9eb +050700d7d8d2e6e6e6f6f6f8fbfafffdfcfffffefffffffffffffffffffffffffdfffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecddebecdaf0efddf6e9e0f0e9e1e4f4eadaf1e9e2f2f29598a1fff7ff +fffaff001b1c00170c00210f001609000009fff8f1ffffc3f4e894ffffb8d4cb92080300 +ffffea0a0a02fcfbfffefefff0f2fffefdfffefefffffefffffffdfffef7fcf8effffff8 +030000fffcf3fffff3fbf9eaffffeffffeeaffffe7ffffe7fbfbe1ffffe8ffffe6ffffe8 +f1f1d7ffffeaffffeaffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe7fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fcfbe6f2f1dcffffecffffecffffecfcfbe6ffffecffffecfaf9e4 +ffffecfffee9ffffecfefde8ffffecffffecffffecffffecf3f2ddffffeaffffecfffee9 +ffffecfefde8f8f7e2ffffecffffecffffecf7f6e1ffffecfcfbe6ffffecffffecffffeb +f4f3def7f6e1ffffecfefde8fbfae5f4f3defafae2ffffe1ffffe1fdffe5fcffe7fcffe9 +fcffeafffee9fffde7fffde5fffde3fffde3fffde3fffee5ffffe7fcffeafcffeafdffe7 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5f8f8defefee4ffffe8ffffe5ffffe8 +ffffe6f3f3d9ffffeaffffecf4f3deffffecfffee9efeed9ffffecffffebffffecfffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9ffffe7ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe9fdffe8ffffedf6f9e8000200 +b4b5afc7c7c7e2e2e4faf9fffcfbfffffefffffefffffffffffffdfffffdfffffbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff1ebddf4e8daf7ebdff3eae1e7ede3daf9ead3f4ebe3f1f49c94a1ffe7fefffbff +00120e6ad1bc007a5e7eddc900040d5e433a5e4a03ffffa5f0e490ffffc10f0700fff9df +f5f2e906050af0effdfcfdfffaf9fffefefffffefff0efebfffff6fffff4fffff6040000 +fffcf3fffff3fcf9eaffffeffffdeafffee7ffffeaf7f5dcffffe8ffffe6f1efd6ffffe8 +eeecd5f7f5defffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5 +fffee5fffee5fffee5fffee5fffee5fffee7fffdecfffdeefffdeefffdeefffdeefffdee +fffdeefffdeefffff1fcf9eaf2efe0fffff1eeebdcf9f6e7fffff1f4f1e2fffff1fffced +fefbecfaf7e8fffff1fcf9eafbf8e9f4f1e2f2efe0fffff1fcf9eafffdeefffff1f0edde +fffeeffffff1f2efe0fffff1f9f6e7f2efe0fffff1fefbecf2efe0fffff1fbf8e9fffff1 +fffff1dedbccfffff1fffff1110e00fffee9ffffe0ffffdcfdffe0fcffe1fcffe5fcffe7 +ffffe7fffee7fffce5fffce3fffce3fffce3fffde3fffee5fcffe7fcffe7ffffe5fffee5 +fffee5fffee5fffee5fffee5fffee5fffee5ffffe8ffffe6f0eed5ffffe8fffee5fcfae1 +ffffe8f2f0d9fbf8e7fffff1f3f0e1fffff1fcf9eafffff1f3f0e1050200fffdeefffdee +fffdeefffdeefffdeefffdeefffdeefffdecfffee7fffee5fffee5fffee5fffee5fffee5 +fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5 +fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5 +fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5 +fffee5fffee5fffee5fffee5fffee5ffffe5feffe6fbffe6ffffedf9fceb0002009b9c96 +b1b1b1d9d9dbf9f8fefcfbfffffefffffefffffffffffffdfffffdfffffbffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1eae0f2e9e2f2e9e2f1eae0 +efebdfeeecddeeecddeeecddeeecddefebdfefebdff1eae0f1eae0f1eae0f1eae0efebe0 +f1ebdff1ebdff1ebdff1eae0efebe0efebe0efebe0efebe0efebe0f1ebdff1ebdff1ebdf +efebe0efebe2eeebe2ecece4ecece4eeece0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f3e9ddf9e5dafce8ddf4eae0e6eee3dcf8ecd5f2ede7eef49f92a3fff4fff4f5ff00180f +1a92774fdcba107e65000709fffbedffffbdf9e58cffffb8eeda9f0d03000604000a0900 +0000000a0b1deeeefffffcfffaf9fffcfffbeff2e9fffefffcf3f6fffefb030000fffcf1 +fffff3fcf9e8ffffedfffee9ffffe70402000808000402000303000e0c00ffffeaf3f1da +ffffeafffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffeeafffdecfffdeefffdeefffdeefffdeefffdeefffdee +fffdf0fffbef0301000f0b000301000e0a00fdfbee0400000907000400001a180bf8f4e8 +fbf9ecfffff30301000501000907000e0a00f1efe2fffef2faf8ebfffff3f0eee1fffff3 +f6f4e7fffff3fffff2fffcf0030100fffef2fffff2fffcf0030100fffff3fcfaedfdf9ed +fffff3f8f4e8fffff3040000ffffefffffe3ffffe0fdffe1fcffe5fcffe7fcffe9fdffea +fffdeafffce9fffce9fffce7fffde7fffde7ffffe7fcffe9fcffe9fffee9ffffe7fffee9 +ffffe7fffee9ffffe7fffee9ffffe7f7f5e0ffffeaf1efdaffffeafbf9e4ffffe9f2f0db +0d0c00040100030100110d01030100fdf9ed030100fffef2030100fffcf0fffdf0fffcf0 +fffdf0fffcf0fffdf0fffcf0fffdecfffee9fffee5fffee5fffee5fffee5fffee5fffee5 +fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5 +fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5fffee5 +fffee5fffee5fffee5fffee7fffee5fffee7fffee5fffee7fffee5fffee7fffee5fffee7 +fffee5fffee7fffee5fffee7ffffe5fbfee3f9fde4feffecfdffef03050091928cababab +dbdbddf8f7fcfbfafffffefffffefffffffffffffdfffffbfffffbfffffdffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff2e9e2f6e6e7f6e6e7f3e8e4efebdf +eceddbeaefd9eaefd9ebeedbeeecddefebe0f2e9e2f2e9e4f2e8e6f2e9e4f1eae4f2e9e0 +f5e8dff6e9e0f1e8e1f4ede7f6f1edede8e4e6e1dbf0e9e1f2e9e0f3e9e0f2e9e0f1eae4 +eeeae7ebebebe7ecefe8ecedecece4efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff3e9dd +fce4d8ffe6dbf9e8deeeeae1e7f2ece1ededeeeaf89f92a6fff8fff0ffff001a115cd7bb +0089655dcfae001d13f8f9e7ebdba8fffcc36c401bfff8d4e1d8a1ffffcdf3f5cdfffff3 +000015fbfbfffffbfff6f6f4f5ffec000900fffafffff3fffffcff010100fffdf1ffffef +fbfae5ffffeaffffe7fdffe7f3f2ddffffed111000f5f6e4ffffedffffecf4f3deffffec +fffdeef7f8eafffff3f5f6e8fdfbeefffff3f6f4e7fffff3fffff2fdfef0f3f1e4fffff3 +fffef1f3f4e6fffff3eff0e0ffffeff7f9e4fffeecfeffedfefdebfdfeecffffeffbfcec +040200fffff1f4f2e5f7f8eafffff4fcfcf0030100fffff3f9f7eaf9faea090700f8f9e9 +030100fffff1f7f5e6fffff1fffff1f6f7e7fffff1fffff1f7f5e6fffff1fcfaebfeffef +fffff3f0f1e3fffff3010200f6f4e7fffff3fffdf0050600fffff3f2f3e5f2f0e3fffff3 +f9f7eaf3f4e6090700fefff1fffff1f4f5e3f9faeafffff1f5f6e8fffff3f8f9ebfbf9ec +fefceffffdf1fffff3fbf9ecfffff3fffff3fffff3f6f7e9fffff0ffffeff9f7e8ffffef +f9f7e8f5f6e4fffff1ffffeff6f4e5ffffeff9f7e8f8f9e7fffff1f8f9e7fefced010200 +fffff2f5f6e8fffdf0fffff3f8f6e9fafbedfffff3030400fffff3eff0e2fffff3f9faec +f9f7eafffff2fbf9ecffffeffffee9ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe7ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7fffee9ffffe7 +fffee9ffffe7fffee9ffffe7fdffe7feffe8fcfee9feffef010100908f8aaaa9a7d8d6d9 +f8f6f9fefcfffffefffffefffffefffffffdfffffbfefdf9fffffdffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc7 +0837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff2e9e2f9e5e7f9e5e7f5e7e4efebdfebeed9 +e8f0d8e8f0d8eaefd9ecedddefebe0f2e9e2f3e8e4f3e8e6f2e9e4f1eae2f2e9e0fbefe1 +f7ebddefe7dcebe7deebe8e1ece9e2f1ede4f8f1e7f3e9ddf5e9dbf3e9ddf2eadfeeebe4 +eaece9e5edefe7edebecece4efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff2eaddf8e6d8 +fbe9dbf4eadeebebe1e8f1ece5eaedf0eaf69e92a6fef5fff0ffff00160e187f6a74e7ca +18765c000d04fbfff4ffffdcffffd1543d14ffffd1f5ffc8deffbdf1ffdaecffe900101a +f2f8fffffafffffefb000900000800fffafffff5fffffcff010100fdfdf1ffffeff9fbe3 +ffffe8fdffe5fdffe7ffffedffffee010200fcfdedf7f8e8feffeb0d0f00ffffedfafbed +fffff30f0f05fffff4010100010100010100010100fffff6f5f5e9f9f9ef030300030300 +040400fffff5fafbedf8fae5010300ffffedffffedf8fae5ffffedfcfdeb010200fafbeb +f8f9e9fffff3fffff3f2f2e6f7f7eb0e0e02e7e8dafffff1f6f7e7050600fffff1010200 +fffff1fcfdedfeffeff1f2e2fffff1e5e6d6fffff0fffff1fffff1040500010200040500 +fcfdefeff0e2f6f7e9090a00fdfef0010200eceddffcfdeffffff20f1002050600010200 +fffff3010200010200010100060600fffff6f0f0e4fffff6010100111107010100fefef4 +f7f7eb010100010100010100020200ecece2fffff4fbfcee0102000d0e000102000d0e00 +fffff3fcfdef010200010200090a00fffff3ebecdefffff2fffff3f0f1e30c0d00fbfcee +fffff3f5f6e8f8f9ebfffff3010200fdfef0010200fffff3fafbed010200070800010200 +fffff3eff0e2ffffefffffe7ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe7 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fdffe7feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9 +fefcfffffefffffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db +1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff2e9e0f8e6e2f9e6e2f5e8dfefecdbebefd8eaf0d6 +e8f0d8eaefd9eeeddbf1ebdff2e9e0f3e8e2f2e9e0f2e9e0efebdfefecdbeee8d2ece6ce +eeecd7ebecdae5e8d7e9ecdbedeedce9e7d2f2ecd4f3ecd2f5ebd0f3ecd2efedd8eceddb +e8eee0e8eee0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddeeebd8eef0db +e6f2dee0f1e1e0f6eadfeeebedecf49c94a3fffafff1f9ff00161400160e00170b002119 +000407fcfffbe1fedfe9ffd8eeffc1174e00237e1e177a281c6436003016000e00f4fffa +fff7fafff4faf8ffff000600fdfff4fefaeefffff8010100fdfdf1ffffeff9fbe3ffffe8 +fdffe5fdffe7ffffedffffee030400fffff1fffff1ffffed010300ffffebfafbebf9faec +010100fafbed060600fffff3f4f4e8fffff3010100fffff3010100fafbedf5f5e9fffff3 +010100fffff1ffffed010300fafce6ffffecffffececeed8ffffed0a0c00fcfdebfbfcea +e7e8d8f1f2e2fcfdeffffff3030400fffff3f8f9e9ffffef010200f4f5e3ffffef010200 +010200010200ffffeff9fae8ffffeff5f6e4ffffef010200e0e1cfffffeff4f5e5101101 +fbfcecfffff1f3f4e4010200fffff1fffff1ebecdc111202eeefdff1f2e2fffff1eaebdb +010200fffff3fffff3fffff2010100fffff3f0f0e4f5f6e8fcfcf0fffff3010100f3f4e6 +101004fbfceefffff4fefff1121206f6f7e9050600f9faeafffff1fffff0060700f3f4e4 +010200fffff1fffff0f6f7e7010200fffff1f8f9e9f0f1e1fffff1010200050600010200 +080900010200fffff1010200f6f7e7070800fbfcec010200feffeffbfcecfeffef010200 +fffff1fdfeecffffe7ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7fdffe7feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcff +fffefffffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff3 +1e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff2eadff8e7ddf8e7ddf3eadbefecd9ebefd8eaefd8eaefd8 +ebeed9eeeddbf1ebddf2eadff3e9dff2eadff1ebddeeecddeeedd9eeecd3ededd3f1f5de +f1f6e0e5eed9eaf3deeff4dee3e5cdf1edd0f3eccff5eccdf3edcdf2edd0efedd4ebefd8 +ebeedbeeecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdde9eedae7f3dddff5de +d9f5dfddf8e9dcf0e7eaeef19b969dfffafffbfdff00050c00090ce9ffff00060b01000b +f8fcfde3fff3286e3028771c54b85554d6800c9253005837247660001b00d9e5cffffaf8 +fff3fffefdff000912f3ffeefbffecfffff6010100fdfdf1ffffeff9fbe3ffffe8fdffe5 +fdffe7eef0dbffffef080900f4f5e5f4f5e5ffffedffffec010300feffed101101f3f4e6 +fffff1010200f6f7e7fffff3f9faea010200f8f9e9010200060700010200171808010200 +fbfceafcfee8ffffeaf5f7e1f5f7e1fbfde7ffffecfdffea010300f7f9e4ffffef010200 +090a00171808eceddd0a0b00010200010200070900ffffefffffedf0f1dfffffedffffef +ffffed010200ffffedfbfceaffffedffffef080a000f1000010200090a00010200fffff1 +f8f9e7fdfeee070800fffff1eeefddfffff1050600fffff1ffffefe4e5d5ffffef010200 +fcfdedf8f9e9fdfeee0d0e00ebecdcfffff31112020607000102000c0d00fdfeee060700 +f4f5e5fffff3f6f7e7010200fffff1010200fbfcecf6f7e7fcfded0e0f00fffff1050600 +080900010200080900141505fffff1f2f3e3fffff1f8f9e9040500edeedeffffeffffff0 +fafbe9f3f4e4111200eaebdb010200fbfcec030400010200070800020300080900f7f8e8 +fdffeaffffe7ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7fdffe7feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffeff +fffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bc +e2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff2eaddf6e9d9f8e8d8f3ebd8efedd8ebefd8eaefd8eaefd9eceddb +efecddf1ebddf2eaddf2eaddf1ebddefecdbeceed9ebeed9ebefd8e8edd7e5eedbe0ebdb +dbe9dae0eedfe6f1e0e7ecd8eeeed6f2edd0f3eccff5eccdf3eccff1edd0efedd4eeedd8 +efecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeddce7f3dfddf6e0d8f5df +ddf8e7dcf0e5eaefeb99979afffdfffffdff060411eeedfb01000efffbff04000ef9ffff +33603f90dea456bb77088245006e4d008b7900857b003932000b01fffcf4fff3f4fff4ff +fff2ff08091eeafefcdcf2e5fbfffb010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7 +ffffedf7f8e6010200fcfdedfffff1eff1dcffffec030500ffffef010200fffff1ffffef +010200ffffeefbfcecf4f5e3060700f7f8e6080900f5f6e4f7f8e8eaebd9fffff1ffffef +feffeaf3f5ddffffeafdffe7eff1d9ffffeaf7f9e3151701eceed8ffffedfafce7f1f2e0 +010200ffffef010200ffffeff9fbe6ffffecffffedfafce6ffffedffffecebedd8eef0da +060800ffffece9ebd6fbfde7ffffec010300fcfee9f9fbe6f6f8e3ffffedfcfdebf7f9e4 +010200ffffed010200ffffedf4f5e3080a00eff0defbfde8fafbe9f1f3de040500ffffef +ffffeff4f5e30d0e00f8f9e7010200f5f6e4eff0e0ffffef010200ffffef010200ffffef +fffff1f9fae81a1b0bf6f7e7020300fffff1fcfdedf8f9e9010200feffef010200f3f4e4 +f7f8e8f6f7e7f7f8e8ecedddfffff0fffff1eeefdf0c0d00ffffeff5f7e2feffedffffed +fafbe9010300ffffef060800ffffef0e1000f2f3e1ffffecfafbe9fbfde8ffffefffffed +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +fdffe7feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffeff +fffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8ff +f4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff2ebdbf6e9d6f6ead4f2ecd6efedd8ebeed9eaefdbebeeddeceddfefebdf +f2eadff3e9ddf2eaddefecddeceddbeaefdbe8efdde3ebdce8f2e9e3f0e9e3f2ede8fbf9 +e1f4f0dfebe7eaf4ebebeddfefecd9f3ebd6f5ead4f5ead4f3ebd6f1ecd8f1ecd9efecdd +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff0eadeedefe1e2f3e0dcf3dfe1f6e5 +e1efe2eaefe8979996fbfffef7f6fb070007190619f5ddf51d0d2700001535524e8dcc9f +5dbd7d1b945e007a5700515035d1e04ae7f85dcedc000710ffeef7fff7fffff6fffcecff +000013eeffffedfffafbfffb010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7ffffed +e5e6d4090a00fffff1e4e5d5ffffedf6f8e2f7f9e3010300ffffedffffefe7e9d4010200 +ffffedf8f9e7ffffed010200ffffed010200ffffecfbfceaffffed010200eef0dbffffea +010300ffffeaffffeaffffeaeef0d8f9fbe5e7e9d3161802f1f3ddffffecfafce6151702 +f9fbe6050700fcfee9ffffecf8fae4f0f2dcfeffeaffffecf8fae4f6f8e2ffffec010300 +feffeaffffecffffecfafce6080a00ffffecffffecf7f9e3030500ffffed010300ffffed +f8fae4ffffed090b00fbfde80f1100feffebffffecffffedffffec010300e2e4cfffffed +ffffed010200ffffed0d0e00f7f9e4ffffefe9ebd6151604f0f2dd040500ffffede9ead8 +f6f8e3050600f6f7e50f1000e6e7d7fffff1fffff1010200fffff1010200fffff1fffff1 +fffff1010200fffff1fbfcecf6f7e7f8f9e9010200ffffedffffedeef0dbfcfee9ffffed +010300f6f8e3010300f4f6e1010300ffffedfeffebffffed010300ffffecf7f9e3ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5fdffe7 +feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffeff +fffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2 +e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff1ebdbf5ead4f5ebd2f2ebd8efecd9eceddfebede0ecece2eeebe2f1eae2f2e9e0 +f3e9dff2eadfefebdfebeddfe8efdfe5efe4eaf4f5edfaffd6e6f3d2e4f2e2f7ffd3e9f7 +ccdce9f0faffe8ecefeeeae9f2e9e4f5e8e0f5e8dff5e8dff3e9e0f2e9e0f1ebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff3e9dff9e4dffae9e2edede1e6eedfebf1e3e8ecde +ecefe4949c91f7fffbebf4f109000717001411000e0400130006150027182d904f038130 +007942004d352bd6e739e5ff3cd7ff003e67000a27fff9fffff2ffffe2fffff6ff00000c +f2fff3dff8dafcfff6010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7fbfde8ffffef +020300f8f9e9fffff1eef0dbffffebffffea020400feffeaedefdaffffec010300030500 +010300010300fdffeaf5f7e1ffffed0103000406000a0c00f2f4dfffffecf7f9e1101300 +f5f8ddeff2d7ffffeaffffeaf7f9e1ffffeaf5f7df0103000103000103000d0f00f4f6e0 +010300fafce6fdffe7ffffeaffffeaf9fbe3080a00010300292b13010300ffffeaf4f6de +ffffeaf8fae2f4f6def2f4dc0a0c00010300010300ffffeaffffec010300ffffeceef0d8 +ffffec010300feffeaf6f8e0010300090b00010300f6f8e0030500ffffecffffecffffec +070900f1f3ddf9fbe6010300010300101200010300f5f7e1010300ffffecfcfee9ffffec +050700f6f8e3fafbe9010200010200010200101100f2f3e1ffffef010200010200010200 +ffffefe9ead8ffffefeaebd9ffffef020300fcfee9fcfee8ffffecf8fae4f1f3dd0a0c00 +ffffec080a00ffffecffffec010300090b00010300ffffebfdffe9ffffecffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe5fdffe7feffea +fcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffb +fffffbfefdf9fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eada +ebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f1ebdbf3ebd6f5ead4f2ebd9efebdfecece2ecebe6ecebe7eeebe6f2e9e4f3e8e2f3e9e0 +f1eae0eeece0eaede2e5efe4e3efebe2eff8d4e3f69dafc78398b399b1cd91a9c59aaec7 +dae9fee4ebfbeaeaf4efe9edf3e7e7f5e7e6f5e7e6f5e7e6f2e9e4f1eae0efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff5e8dffee2e1ffe5e4f4eae1edebdff2eee2eceaddecf0e2 +909e8fe6fceff5fffdfef4fcfff3fffff4ff05011800232ec0ffff4dda9800893e009368 +32e9d534f7f3009c9b008c86038681000e19fcfdfffce7fffff4ff08000c040003000500 +f9ffedfefff6010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7f9fbe6ffffefedeee0 +fffff1fafbebffffecffffec010300ffffecf4f6e0ffffecffffec050700ebedd7ffffec +f7f9e3fdffe9ffffecf3f5dffbfde7ffffebf8fae4ffffecfbfde7ffffeaffffe7f4f7dc +ffffe8ebedd5ffffeaffffe9f4f6deffffe9ffffe9ffffeaf5f7dfffffeaffffeafcfee6 +ffffeafdffe7fcfee6ffffeaf8fae2f5f7dfffffeaeef0d8ffffeaffffe9ffffeaeef0d8 +ffffeafeffe8ffffeafdffe7fcfee6ffffeafbfde5ebedd5ffffeaffffeaf6f8e0ffffea +ffffeafdffe7f5f7dfffffeaf7f9e1fcfee6ffffeaf6f8e0f6f8e0f5f7e1ffffecf5f7e1 +ffffecffffecf2f4deffffecfcfee8ffffecffffecfdffe9eff1dbffffecf7f9e3f8fae4 +ffffecffffeffafbe9ffffeffcfdeb020300f8f9e7ffffeffeffedffffeeffffeffafbe9 +ffffeffeffedffffeff8f9e7f9fbe6ffffedeef0daffffecf9fbe5ffffebffffecfafce6 +f2f4defbfde7f2f4deffffecffffecfdffe9fbfde7fcfee8fbfde7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe5fdffe7feffeafcfee9 +feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffbfffffb +fefdf9fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dc +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdd +f3ebd8f3ebd8f1ebddefebe2ecebe9eceaebeeeaebefe9e9f0e5e3fdf2ece8ded5fbf4ec +e9eae4e3e9e5dbe7e5e4f1f7e6f3ff8c9cb3dcf0ffa8bfde89a6c698b5d598b1cf8195ae +dbe8fbe5e9f5f4f1f8efe6e9efe3e3f5e7e7fceeeeece1dff1eae0efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff5e8dfffe1e1ffe4e4f9e8e1f1e8dff6ece2ede9ddeaf0e28d9f8f +ebfff8ebfff8fffdffffeefefff6ff0000129ed5da66ddca34f2c410f2c41effee20ffe8 +00965600b0490bef6427d961001900f8ffffeff9fffcfefffffbf8ffeee9fff5f8fffcff +fffefd010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7ffffedf8f9e7fcfdeffffff1 +eeefdfffffedffffec010300ffffecfbfde7ffffecf8fae4010300ffffecf7f9e3ffffec +ffffecfbfde7ffffebffffecf7f9e3fafce6ffffecf8fae4f7f9e1ffffeaf1f3dbf8fae2 +ffffeafafce4fcfee6ffffeaf9fbe3ffffeaf3f5ddfdffe7f8fbe0ffffe8ffffe8fcffe4 +f3f5ddffffeaf2f4dcf6f8e0ffffeaffffeaf4f6deffffeaf0f2daffffeafbfde5f4f6de +ffffeaeef0d8f5f7dfffffeaf6f8e0ffffeaf8fae2fafce4ffffe9ffffeaeef0d8f8fae2 +ffffe9ffffe9fdffe7fbfde5ffffeafbfde5feffe8fcfee6ffffecf5f7e1ffffebffffec +f7f9e3f8fae4ffffecf5f7e1fafce6ffffecf6f8e2ffffecffffecfafce6f7f9e3fdffe9 +feffed010200040500101100f1f2e0fafbe9ffffeffafbe9ffffeffeffedfafbe9ffffef +ffffeff1f2e0fbfceaffffedf7f9e4f8fae4ffffecffffecf6f8e2fbfde7f1f3ddffffec +fcfee8fdffe9eff1dbffffecfbfde7f5f7e1ffffecf3f5dfffffecf9f8e3ffffeaffffec +f1f0dbedecd7ffffecfaf9e4ffffecf7f6e1ffffeaffffeaf7f6e1fefde8ffffeaffffec +ffffecffffeaffffecf4f3deffffecedecd7f8f7e2ffffecfbfae5fffee9f7f6e1ffffec +ffffebffffeafefde8ffffe9ffffe6ffffe6ffffe8f4f4daf8f8deffffe8ffffe8fdfde3 +ffffe6fefee4fdfde3ffffe8ffffe7ffffe8ffffe5ffffe8fdffe7feffeafcfee9feffef +010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffbfffffbfefdf9 +fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf2ebd9 +f2ebd9efebe0eeebe6eeeaebeee9edefe9edf1e8e9fdf2eee6d9d1fcf2e8eeeae1e7e9e4 +eaf2f4f5ffffd9eaf496a6b3deefffedffffd9f3ff85a4c18fb1cde0ffffeaffff98a9bb +e6f0fadcdde2efebeafcf4f1f6ede8e5dad6f6ede6f1eae0efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff3e9dff9e4dffce7e4f6e9e1f1e8dff5ece3eceadee7f2e48aa18fdeffee +eefffdf4f2f7fff9fffff7ff00000e97cacd1e867d00857345feee1fd6d400947e08b367 +14c24927e54535c93d002500fbfff8f5ffffecf5fcfdf4edfffaf3fff9fbfffafffffdfd +010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7f1f3deffffeff8f9ebf8f9e9fffff1 +f8fae5ffffecfeffe8f5f7e1ffffecf6f8e2ffffecfafce6f4f6e0ffffecf6f8e2eef0da +ffffeceef0daffffecffffecffffecedefd9ffffecf1f3ddf6f8e2ffffecffffeafcfee8 +ffffeaf4f6defbfde5ffffeae8ead2ffffeaffffe9ffffe8e7eacfffffe8fafde2ffffea +e7e9d1ffffeaffffeafeffe8f6f8e0eef0d8f4f6deffffeaf0f2daf7f9e1feffe8fbfde5 +ffffeafdffe7f8fae2fbfde5f6f8e0f3f5ddf8fae2ffffeae4e6ceffffeaffffeaf3f5dd +ffffeaf3f5ddffffeaf5f7dfffffeaf6f8e0ffffeafcfee8ffffecf2f4deffffecfeffea +ffffecfafce6ffffecffffecf2f4deffffecf9fbe5f1f3ddffffecffffecffffebfdffea +fcfdebffffeef1f2e0fcfdebffffefedeedcffffefffffeeffffeeffffefebecdaffffef +ffffeffeffedf5f7e2ffffedfdffe9fcfee8dcdec8ffffecffffecffffecfcfee8ffffec +fcfee8ffffecf7f9e3ffffecffffebf2f4defdffe9f8f7e2ffffecffffeaf0efdaffffec +ffffecfaf9e4f9f8e3edecd7ffffecfffee9fbfae5ffffecffffeaf6f5e0f6f5e0f7f6e1 +ffffecf7f6e1ffffecf8f7e2fdfce7ffffece8e7d2ffffecfbfae5ffffecf0efdafdfce7 +ffffeaf8f7e2f4f3defafae2fafae0fafae2ffffe7ffffeaf0f0d6ffffe9ffffe7fdfde5 +ffffe8fefee6ffffe8ffffe7f7f7ddffffeaf3f3dbfdffe7feffeafcfee9feffef010100 +908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffbfffffbfefdf9fffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddf1ebdbf1ebdd +efeae4eeeae7eee9edeee9edf1e8e9f2e9e4f0e3dafef2e4e8dfd0f4f0e5f5f7f4cad3d8 +deeefd91a3b1c5d4dbf2ffffe9ffffdffcffc9ecffe3ffffe0ffffe2ffffe4fcff899b9d +ecf5f2f0f3eae3e1d5ebe7dbf2ecdef4eee0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfedebdff0eee2efede1edebdff1eee5e8ebe0e3f3e689a193e7fff9f1ffff +fbf9fefff7fffff0ff0a0815001214000f13000d1e000e21000915000c06001800001700 +001d00001900000600e1d8d1fffafffffbfffafdfffcfffbfffdeafdf8e4fffff6010100 +fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7ffffedffffeff9faecfffff0f6f7e7ffffed +ffffebf4f6deffffecffffebebedd7ffffebffffecffffecf8fae4fcfee8ffffecffffec +ffffecf2f4deebedd7f7f9e3ffffecf3f5dfffffedfafce7f5f7e2f3f5dff6f8e3feffea +ffffecfbfde7ffffecffffecffffeaeaecd4ffffeaffffeaf5f7dfffffe9edefd9ffffec +f9fbe5ffffebf4f6e0ffffebffffecffffeceff1dbffffecffffecfdffe9fcfee8f4f6e0 +feffeaffffebffffeaf9fbe3ffffeafdffe7f2f4dcffffeafdffe7eceed6ffffeaffffea +f7f9e1ffffeaf6f8e0fbfde5ffffe9f3f5ddf8fae4ffffecf0f2dcfbfde7ffffecfcfee8 +fdffe9fafce6ffffecf4f6e0ffffecfeffeaf6f8e2ffffecf4f6e0fdffe9f8fae5ffffed +fbfde8ffffedfbfde8ffffecffffedf2f4dff5f7e2ffffedfafce7ffffedf1f3deffffed +f1f3deffffedffffecf4f6e1ffffedffffedfdffeaf1f3defeffebfafce7ffffedeaecd7 +fdffeaffffecffffedfeffebf2f4dfffffedffffececebd7ffffebffffede9e8d4ffffed +f5f4e0faf9e5ffffedf5f4e0f0efdbffffedf2f1ddffffedf3f2deffffedffffedf6f5e1 +ffffedf8f7e3ffffedfefde9efeedaffffedf0efdbffffede5e4d0ffffedffffedfffeea +f9f8e4ffffecffffecf5f5ddffffecffffeaeae9d4ffffeaf7f6e1ffffe8f5f4dfffffe9 +f3f2ddffffeaf3f2ddffffeaffffeaffffeafdffe7feffeafcfee9feffef010100908f8a +aaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffbfffffbfefdf9fffffdffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddf1ebdbefecddeeebe4 +eeeae7eeeaebefe9e9f2e9e4f3e9ddf5e8d5f5ebd2fffee7e8e5d4e2e7e1e7f4fa92a5b6 +d1e4f5f4fffff3ffffeeffffe7ffffe4ffffe2ffffafd6e7b1d5e3e8fffff0ffff95a19d +e2eadfeceee1dbdcccfdfbeceae8d9efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +ebeddfe4efdee6f3e1ebefe1ebebe1f1eee7e8ebe4e3f3e98a9f96f0ffffe2f1eefffdff +fff3fcfff9fffffdffeefdffebfefffcfcfffff7fffff4ffffedf3fff2effffff4fffef4 +fffaf1fff7f0fffafafff9fffcf4fff4fefff5fffffbfdefffffeffffff8010100fdfdf1 +ffffeff9fbe3ffffe8fdffe5fdffe7f2f4dfeaebd9fffff3fffff1fffff1ffffedfcfee8 +ffffeafcfee8f8fae4ffffedf0f2dcf7f9e4f7f9e3ffffedf4f6e0fbfde8f8fae4fafce7 +fafce6ffffedf7f9e3f3f5e0ffffedf2f3e1ffffefffffefffffefffffeff7f9e4ebedd8 +ffffeceaecd6ffffecf6f8e2ffffeaf8fae2f8fae2fafce4ffffeafdffe9ffffecedefda +ffffec0b0d00f1f3ddffffedf0f2dcffffec111300010300ffffecf9fbe6ffffebffffed +fdffe9ffffebedefd7f7f9e1ffffeaffffeaffffeafeffe8ffffea010300f8fae2ffffea +f9fbe3fdffe7ffffeafcfee6ffffecfafce6ffffecffffedeff1dbffffedfcfee8ffffed +f5f7e1ffffed010300eff1dcfcfee8ffffedfdffe9ffffedfbfde8ffffedffffedfdffea +f3f5e0f9fbe6fbfde8f6f8e3ffffedfcfee9010300ffffeceef0dbffffedf4f6e1ffffed +e5e7d2f3f5e0ffffedf7f8e6f3f5e0ffffefffffedffffefffffedffffeffeffebffffef +edefdaf5f6e4eceed9ffffeff6f8e3fefde9ffffedfaf9e5f5f4e0ffffedfbfae6ffffed +ffffedf8f7e3f4f3dfffffedf4f3dfffffedffffedffffedfcfbe7ffffebffffedffffed +ebead6fbfae6ffffedffffedffffedfcfbe7fffeeaffffedf8f7e3f8f7e3fbfae6fefde9 +f6f5e1f9f8e4ffffecf8f7e3ffffebffffedffffecfefde9fffee9ffffedffffecfffeea +ffffecffffedf9f8e3fcfbe7f7f6e1fdffe7feffeafcfee9feffef010100908f8aaaa9a7 +d8d6d7f8f6f9fefcfffffefffffefffffefffffffbfffffbfefdf9fffffdffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddefecdbefecddeeebe2eeebe6 +efeae6f1eae2f3e9ddf5ead4fff7d7e8debbf2eccae9e9d1eaf2e7e2f1f68da2b7dff4ff +f2fffff7ffffecffffeaffffd4f8ffa5cee0b2dbedbbe2f3c4e4efe3ffffefffff8f9c95 +e1e8e0fefff6dadccfeeeee2eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeaeedf +ddf3dce0f6dfeceee0f0e9e1f2ede9e9e9e7e6f0ef8e9c9ceef9fbf9ffff8b898e797279 +8a84888783848080808b8c8e81858e777582907e8c9b8494998b9cfbf4fffefdfffffbff +ffeefafff3f9fff8f9fefffdf5fffff2fdfff3f1fffffbfffffdff010100fdfdf1ffffef +f9fbe3ffffe8fdffe5fdffe70b0d00070800050600010200eff0e0fbfde8fcfee8f7f9e3 +fcfee9ffffecffffeff2f4dffeffed0f1100e8e9d7ffffedffffeff7f9e4fafbe9fcfee9 +f5f6e4f8fae5ffffeef8f9e7fffff1f4f5e5010200010200f3f4e4ffffefffffef010300 +1a1c07f3f5dffcfee8ffffecffffecf9fbe5fbfde5f7f9e3fcfee9fcfee9ffffeefcfee9 +010200ffffed010200ffffed010200ffffedf7f8e6ffffed060700fcfee9f7f8e6f8fae5 +f0f2dcffffecffffecf8fae4ffffece7e9d3ffffecf8fae4090b00fbfde7f4f6e0f8fae4 +ffffececeed8ffffecf1f3ddffffedfbfde80102000b0d00010200e5e7d2ffffefffffed +ffffee040600ffffeffdffeaffffef010300ffffeefcfee9fcfee9f1f3deffffed050700 +ffffedffffedfbfde8fcfee9ffffed010300f7f9e4ffffed0103000204000b0d00ffffed +fbfceaffffef0405000102000e0f00f6f7e5f4f5e5f5f6e4010200010200010200ffffef +fffff1ffffef010200070800030200fcfbe7fffeeaffffedf9f8e4ffffedf4f3dfffffec +030200ffffedf0efdbfefde9ffffedf1f0dcffffedf8f7e3f5f4e00504000302000a0900 +ffffedffffed0302000302000f0e00030200030200ffffedffffedfcfbe7ffffedf2f1dd +ffffed030200030200ffffecfffeecf6f5e1050400090800faf9e7ffffedffffed030200 +030200ffffedffffeffdfce8fdffe9feffeafcfee9feffef010100908f8aaaa9a7d8d6d7 +f8f6f9fefcfffffefffffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc7 +0837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefecddefecd9efecdbeeece0eeebe2efebe2 +f1ebddf3ebd4f6ebcbf8ecc2f8f0c1ebe6bcffffe0dde5d692a4a6dff5ffeefffff8ffff +f2fcfde8f9ffe7ffffb2d5e9bee6ffb1dbf4b3dbf4b3d6eac7e2f3efffffe4f3f899a3a4 +dce2e2f5f9f8e7e9e4eeebe2efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeaeedddcf4da +e2f5dff0ece0f7e5e3f9e9eaefe6ebeaedf292999ffcfffff5f5fd797a7ff7f8faeaefeb +d3d4cff7eee9efe7e4e2ebe6e0e9e6f9eef2ecdfe6a9a6b1535466e8e8fffbf7fffff9ff +fff6fdfaf1eaf9fbeef4fffaf4fffffdfbfffcf4fffffeff010100fdfdf1ffffeff9fbe3 +ffffe8fdffe5fdffe7030500f1f2e0fffff3f3f4e40b0c00ffffedf8fae4ffffebf6f8e3 +f9fae8f9fae8ffffefffffef010200ffffeff0f1dffdfeecf8f9e7ffffefffffefffffee +feffedffffeffcfdedfcfdeffffff3010200010200fffff3f8f9e9fffff1010200010200 +ffffedf8fae5ffffeceff1dbffffecffffecffffecfcfdebffffeffcfdebfeffed090a00 +ffffefffffeef4f5e3151604ffffeee3e4d2ffffeff4f5e3fcfdebffffeeffffefffffed +eceed8fcfee8f6f8e2fdffe9ffffecf6f8e2fdffe9010300ffffeceff1dbffffecfcfee8 +fdffe9f3f5dfffffedfdfeec050600fbfceaffffeeffffee121301ffffeff1f2e0ffffef +010200f5f6e4fcfdeb0506000e0f00edeedcffffefffffecfbfde8010300101200e5e7d2 +ffffedebedd8ffffedf3f5e0010300ffffed010300feffebffffededefda010300fffff1 +010200fffff1fffff0f6f7e7010200feffef090a00f8f9e9fffff1fffff1010200fffff1 +010200f9faeafbfcecffffef060500fffeeafbfae6f7f6e2ffffedffffed030200030200 +f6f5e1f8f7e3fcfbe7ffffedffffedfdfce8ffffed040300ffffedfbfae6ffffed030200 +ffffed100f00ffffedf9f8e4ffffecffffedffffedfaf9e5efeedaffffebffffedf7f6e4 +060500030200ffffeffcfbe9ffffef131200030200fdfceafaf9e7ffffed1817050f0e00 +f4f3e1f6f5e3ffffedfdffe9feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9 +fefcfffffefffffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db +1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefecddeeedd9eeedd9eeecddeeecdfefecddf1ecd8 +f3edcdf6edc2f4eab5b1a86f9f9c6795976fabb7a3c8dadaecffffd8ecfff1f7fff2f6ff +f4ffffd3e8ffadceefbfe5ffa6d0f8abd2fbb9dbffc6e0ffc9ddf8ecfbffd3dced9097a7 +e0e6f4ebeef5ecebe6efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfebeedde0f2dae9f2dd +fbe6e1ffdfe3ffe4ecf6e2edf0eaf49797a1f7f4fffffdff899194e5f4f1eafff4f8fff8 +f9efe6fffbf2f8fffaf7fff6fbf4e1fff9e395a693eefff9686775fff9fff6f3fcfffdfb +fffbefffffecebffece8fff7f9fffffffdfffffeff010100fdfdf1ffffeff9fbe3ffffe8 +fdffe5fdffe7010300ffffeff6f7e9fffff1feffef010300ffffecffffec090b00030400 +030400eff0def3f4e20102000a0b00010200ffffeff0f1df010200010200010200ffffef +e7e8d6fbfcecf5f6e8fffff4010100fffff3060700fdfeee010200ffffef010200f3f5e0 +ffffed020400010300010300f5f7e1fafce6ffffef0102000d0e00090a00010200f9faea +010200fffff10203000102001c1d0df7f8e8010200fffff1fffff1010200040600010300 +ffffedffffedf4f6e1010300040600010300010300ffffedffffed010300ffffedf5f7e2 +f6f8e3f5f7e2ffffefe7e8d6ffffeeffffeffdfeec010200eceddbffffef010200ffffef +fafbe9ffffeff6f7e5060700f7f8e6f3f4e2ffffedf9fbe5fcfee8030500ffffecffffec +ffffecfdffe9050700fcfee8ffffecffffecf0f2dcfbfde7ffffec030500fdfeee010200 +fffff3fffff3f6f7e90a0b00fffff3010200f8f9ebfbfceefdfef00f1002f7f8eafdfef0 +fffff3fcfdedfaf9e7050400eae9d5ffffedffffedefeedaffffedffffec060500ffffed +ffffedffffedf5f4e0030200ffffedf2f1ddffffedffffedfdfce8faf9e50b0a00fffeea +030200edecd8f2f1ddffffedffffedf2f1ddffffedffffedefeedafefde9030200fffff1 +fffff1030100fffff1f6f4e5030100fffff1080600fffeef080600e6e4d5030100fffff1 +fefcedfefdebfdffe9feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcff +fffefffffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff3 +1e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddefedd8eeedd8eeedd9eeeddbefecd9f1edd2f3eec8 +f6eebda69e5febe4a0ebeaaae2e6b3c6d3b9dcefede2fbffe3f8ffdde9fff5ffffc2d3f1 +adc7eacaebff93bce8caf5ffa4cffcb8ddffa3c2eeb8cff8d7e9ffe3f0ffc1cae7979eb8 +e1e4f3eeeae7f1ebdff1eae0f1eae0f1eae2f1eae2efebe2efebe0efebdfefebdfefecdd +f1ebddf1ebdff1ebdff1ebdff1ebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddde7efdaf0efddfde6e0 +ffe0e3ffe5ecf4e3edeeebf49597a3fffdfff0f2fe7d8b8ef1ffffe4fef5f5fffbfcf5ef +fffdfbf7fffff4fffffcf9f0fffff394a99840554e4b4956534a5bfffefffffffafff7ea +fffdeaf5fff1f0fff8f9fffff8f9fdfffffd010100fdfdf1ffffeff9fbe3ffffe8fdffe5 +fdffe7070900fafbe9f9faecfbfcecfffff00a0c00f0f2dcffffecf9fae8ffffeff5f6e6 +050600fffff1010200ffffefffffeff7f8e6080900ffffefedeedcffffef010200ffffef +ffffeffffff3f9faec040400fbfcee010200fbfcee010200fcfded090a00f9fae8010200 +ffffedf8f9e7ffffed030500ffffed010200fffff1f7f8e8f8f9e9050600fffff1010200 +feffef010200fffff0fafbebfffff1010200fbfcec010200fffff1fafbe9ffffed010300 +f7f9e4131500e7e9d4ffffedffffed121400e5e7d2ffffed111300e0e2cdffffedf8fae5 +fbfde8f4f6e1ffffeffdfeec010200010200fafbe9ffffeff0f1df010200fdfeecf7f8e6 +ffffeff6f7e5010200fdfeecffffedf1f3deffffecf8fae4010300ffffecfafce6f8fae4 +ffffec010300fdffe9f5f7e1fdffe9ffffebfdffe9010300fafce7f5f6e6080900fffff3 +f2f3e5fffff3010200fbfcee060700fffff3fcfdeff5f6e8040500fcfdeffdfef0fafbed +030400030200ffffedfffeeafdfce8f5f4e0ffffedfcfbe7ffffeb060500fcfbe7f2f1dd +ffffedf5f4e0100f00f7f6e2ffffedfefde9f8f7e3ffffed030200f9f8e4ffffed030200 +0a09000a0900030200ffffedfaf9e5ffffedf3f2deffffebffffed030100fcfaebfffeef +040200fffeeffcfaeb030100fbf9ea030100fffff1030100fffff1040200fbf9eafaf8e9 +ffffeffdffe9feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffeff +fffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bc +e2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefecddefedd8f1efd8efedd8edebd6f3eed8f0ebcef7f0c6a49d66 +faf3adf8f2a6ffffbcecf2b4aab692afc2bcdaf3ffd9f3ffd2ecffc8e4ffb3d3fcb8ddff +9dc8f2b6e5ff9fd0f8b1e2ffa7d3ffb0d6ffb6d6ffd3eaffd1e1ffdce8ffb3bbdf8f90a5 +f4ebecf0e3dbeee1dbf1e6e4faeeeef4eaebeee6e4f3ece6f1eae0f1ebddf1ebdbf2ebdb +f2eaddf2eadff3e9e0f2e9e0f1ebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf1eadaf5ecddf7e9e0f4e7e1 +f4eceae9e9ebe6eff48e9ba3f5ffffeaf8ff809199edfeff77868d868f9485848c807f91 +757da27981af7c7ea47d819e80889f091023b9b7cc5c5867fffefffffffdfff8f2141005 +fcfff6eef8edfcfffbf6f8f3fffffb010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7 +010300ffffeffffff2f9faeafdfeee0d0f00fafce6f8fae4010200090a00030400010200 +fffff3010200fafbebfbfcecfdfeee0102000a0b000102000102000b0c00fbfde8ffffef +fffff1f0eedf090700fdfbecfffff0080600faf8e9fffff0030100fffff1040200f7f6e4 +faf8e9ffffef030200fffff1050600f4f5e7fafbedfdfef0010200fffff3010200fffff2 +050600fafbedfffff3f5f6e8050600fafbed010200010200010200010200030400fdfeec +010200fdfeecffffedffffed080a00eceed9ffffecffffecf4f6e0f8fae4ffffecfcfee8 +f6f5e1ffffecffffede7e6d2ffffed0e0d00efeedaffffed030200ffffedf3f2deffffed +ffffed030200f9f8e4fefde9ffffedffffedfbfae6030200ffffedecebd7ffffedfdfce8 +030200ffffedf3f2deffffedffffed030200ffffedfbfae6f7f5e60a0800fffff1f4f2e3 +fffff1030100fdfbec080600fdfbecfffeeffffff1030100f9f7e8fffeeffcfaebfffff1 +ffffef030200f9f8e4ffffebf4f3dfffffedffffedffffed080700f1f0dcffffedfdfce8 +efeedaffffebffffecffffecffffedffffec050400fefde9f9f8e4ffffedfbfae6ffffed +ffffedfbfae6030200ffffedf7f6e2ffffedfffeeaffffed070500fdfbecfcfaeb0e0c00 +f8f6e7fffff1030100fffeeffffff0030100fffff1f6f4e5121001f1efe0fffff1ffffef +fdffe9feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffeff +fffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8ff +f4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddefedd8f1efd8efedd8edebd6f3eed8f0ebcbf7f0c2a69e60ffffb5 +fffba5ffffa8fcffb4d8e4b4b2c3b1b3c9d6cbe6ffd9f7ffafd0fbb7dcff9ac4eebbe7ff +a1d1f5a2d4f59bcdeeafddffadd7fdc1e2ffd6f2ffedffffecfaffd3dbeeacadb2988e84 +f6e6d7fff4eaf9eae5ebdddcf3e9e8ede3e2f5edeaf1eae0f1ebddf2ebdbf2ebdbf2eadd +f3e9dff3e8e2f3e8e2f1eae0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff1ebddf4e8daf8eaddf3ebdeedeae1edefea +e3ece9e3f1f28d9ca1f1fffff4ffff8a96a2edf5ff808392161523c7c0d01712320c0d50 +1319670f135a0608430a0b39000020fefcff585661faf8fbfffffbfffffa010000fffffa +f8f9f4fefffdfefffdfffffb010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe70e1000 +ffffeff3f4e6fffff1fffff1010300ffffec121400fffff1f0f1e3fffff20f1002eeefe1 +101101f8f9e9fffff1f5f6e60c0d00f1f2e0fcfdebffffeffafce7f7f9e4ffffedfcfbe9 +fffff1100e00fffeeffffff1030100fffeeff7f5e60a0800f3f1e2030100fffff1fcfaeb +fbf9ea100e00efedde020300fffff3eff0e2fffff3010200fffff3010200fffff3010200 +fefff1fdfef0fffff3040500fffff3010200fffff1ffffeffafbe9f5f6e4ffffef020300 +f5f6e4ffffedf2f4df010300ffffedffffebdee0caffffecffffececeed6ffffe9ffffed +f4f3dff1f0dcffffecffffed030200ffffedffffed0d0c00fefde9ffffedf6f5e1fbfae6 +070600ffffecffffedf5f4e0fdfce8fefde9030200ffffedffffedffffedffffed040300 +ffffebffffecffffed060500f6f5e1ffffedffffecfffeec030100fffff1fffff1f8f6e7 +0c0a00fffff1030100fffff1fdfbecfffff10f0d00fffff1fffff1fffeefeeeddbfefde9 +060500fcfbe7ffffedffffedf1f0dcffffedf4f3df030200ffffecf2f1ddf4f3dfffffed +ffffedfcfbe7f9f8e4f9f8e4030200f7f6e2ffffedffffedf5f4e0ffffedf8f7e3efeeda +ffffed030200f9f8e4ffffedf6f5e1ffffed030200030200141203030100030100131102 +e9e7d80c0a00fffff1fffdee030100fffff1fefced030100fffff1fffff0faf9e7fdffe9 +feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffeff +fffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2 +e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddefecdbf0efddeeecddedead9f3eed8f1ebcbf8f0bfa79e5bfffda6ffff9f +faf693ffffabffffcac8d6b2a1b2a8bdd3e0bcd5f3afcbf2afcff6b5d9fda9d0f1aedaf7 +aad8f0c6f4ffafdaeda5ccddbedeebc6e1e8e0f3f1cbd9ccb4c0a88e91727e7652f4e7c5 +f1e3c9fff3e0ece0d4faf1e8e6ddd6f1eae2efebe0efecddf1ebdbf1ebdbf1ebddf2e9e0 +f2e9e4f2e9e4f1eae0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff1ebddf1eadaf4edddf2ece0ebebe1ebf0eae3ece9 +e6f0f2909ba1f8ffffeff5ff747683fffcff9a8f9f0b000c200b1c1c0b350b075e000062 +04056102044e04053b171a3bfcfeff47484afffffafbfdf0fffff5020200fffffff8f7fd +e9e9f5fafafffffeff010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7010300ffffef +fffff3edeede010200ffffedffffec010300f8f9e7fffff1fcfded050600fffff1010200 +fffff1f0f1dfffffef010300ffffedfcfee9f2f4df010300ffffecf6f8e3ffffefedecda +040300f7f6e4eae9d7ffffeffbfae8ffffef070600ffffef030200fffeecffffeff3f2e0 +030200ffffef050600f2f3e3feffefeceddd010200fffff1060700f7f8e80c0d00fffff1 +f2f3e3fffff1010200f8f9e90f1000f8f9e9ffffefffffef010200fbfcea040500ffffef +fafce7ffffed080a00f0f2ddffffec121400ffffecd9dbc5ffffeafdffe7f6f5e1090800 +ffffedffffede4e3cf030200ffffedf9f8e40b0a00e5e4d0ffffedffffecfffeea030200 +ffffecfaf9e5ffffedf9f8e4ffffed070600f3f2deffffecf5f4e0faf9e5030200ffffed +f2f1dd030200f7f6e2ffffedffffedf7f6e2ffffef030200ffffefffffeef8f7e5030200 +ffffed0b0a00fcfbe9fffeecf5f4e20c0b00eeeddb030200ffffefffffeff3f2de090800 +f3f2deffffedffffedfffeeaffffecffffed030200ffffedfcfbe7ffffedfaf9e5030200 +fffeeaffffed030200ffffedfffeeaffffedfdfce8ffffec0c0b00fffeeaffffedeeedd9 +030200ffffedfbfae6f5f4e0ffffed0a0900f9f8e6ffffeff6f5e3ffffef0e0d00ffffef +030200f7f6e4f5f4e2ffffeff7f6e4faf9e7090800fcfbe9f6f5e3ffffedfdffe9feffea +fcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffb +fffffbfefdf9fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eada +ebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeecdff0eee1eeece0edeadbf3eedaf3eac9fbefbbaa9e54fdf092ffff9bfff98f +fbf794ffffbce7f0b9b8c6a5b0c4bbc5e0f3b1d0edc5e4ffafcfe8c0e0f5afd0e1aecedb +aacbd4bfdce2b9d5d6cee5dfd1e7dad4e7d3bfcfb4afbf9b9aa378958f5da89c6a84764f +e7dcbcf0e5cffff9eaebe3d8fcf5ebefebe0efebdfefecddf1ebddf1ebdff1eae0f1eae4 +f1eae4efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddf0eadaf1eeddefede0eaece1ebf0eae5ebe9e7eff1 +94999ff8fbfff7f5ff9c94a1fff9ff776070fff5ffffe6f7fff3fff9f3ffe9ecfff2f5ff +f4f8ffd8dbff050926f3f5ff4f514cfefff4eef1e0fffff4010000000002000009050318 +fffcfffffeff010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe70305000102000c0d00 +090a00fafbebffffedeaecd6ffffec0c0d00010200010200090a00fbfcecf7f8e6050600 +101200f7f9e4fbfde8010300101200010300feffeaffffecf7f9e3faf9e5f4f3df141301 +fdfce8ffffeff8f7e3fefdebf5f4e0090800e2e1cdffffef030200040300070600fffeec +f8f7e5eaebd91617050304000304000e0f00f4f5e3020300ffffef010200feffedf8f9e9 +f7f8e60a0b00ffffeff6f7e7010200010200010200ffffefffffefffffee010200010300 +010300010300ffffedfafce6010300f6f8e2ffffecffffeafbfde5ffffedfffeea030200 +070600131200fdfce8ffffed030200ffffedffffecfdfce8f8f7e3050400040300030200 +ffffedffffece9e8d40403000504000b0a00ffffedffffed030200fdfce8f6f5e1ffffed +030200111000030200030200111000fdfce8ffffed060500030200100f00f8f7e3f6f5e3 +f7f6e20403000d0c00191806eeedd9ffffeeffffed0302000302000d0c00ffffecffffec +f5f4e0fffeeafefde9f3f2de030200050400030200ffffedeae9d5ffffec080700ffffed +f1f0dc0302000302000403000a0900040300f1f0dcf3f2de0a0900030200030200ffffed +fefde9ffffedffffecf5f4e0030200fdfce8ffffedfdfceaf0efdb030200ffffed030200 +ffffedffffeff4f3dfffffeff8f7e3030200ffffededecdafcfbe7fdffe9feffeafcfee9 +feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffbfffffb +fefdf9fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dc +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeece0eeeee4eeebe4ede9def4eddbf4eac7fcf0b6ad9e4dfff690ffff8dffff8bfff88c +fffa9ffafcb1e0e8afbacdaf9cbfc1a9d4e4c7edf6bbdce1b2cccdb7cac8b4bfb9b8bfb8 +a8aea4b1b7abbec6b7d1deccc9dac7dcf1dee6ffecf4ffe5fffec3aba05e7d723cfff5c8 +fdf2d4f8f0dbe6ded1efe8deefebe0efebdfefebdfefebdfefebdfefebe0efeae4efebe2 +efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfedebdceeefdfeceee0e9ece1ebf0eae6eae9eaeef197989d +fffdfffaf0fb92808cfff2ffa28291ffe7f6ffddec321031f7f1fff1f7ff1e246ee7eeff +d4d9ff000619fbffff53594ff4f8e9fefff1f9fbee000100fffefff4f2fffffbff000010 +fffeff010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7f7f9e4ffffefe3e4d6f9faea +fdfeeeffffedfcfee8fcfee8ffffedf1f2e0ffffeff5f7e2fdfeecfafce7ffffecebedd7 +feffeafcfee8f1f3ddffffeaffffeaffffeae7e9d1fdffe9faf9e4ffffecf9f8e4edecd7 +ffffedfaf9e4ffffedffffeaf5f4e0ffffecfffeeaffffeafefde9f3f2ddffffedffffed +ffffedf4f6e1feffedffffedf5f6e4ffffede4e5d3feffebffffefffffedf9fae8ffffed +eceddbffffedfcfdebffffefffffefffffefeeefddffffeff0f1dffdfeecf9fbe6ffffed +ffffedf5f7e2ffffecffffecffffecfeffeaf5f7dffbfde5fcfbe7f9f8e4ffffedf6f5e1 +fdfce8ffffebfffeea0b0a00f5f4e0ffffedfcfbe7ffffedf2f1ddffffebf9f8e4eeedd9 +fffeeaffffedffffebfefde9f0efdbffffedf3f2de070600ffffedffffedf4f3dfffffed +f5f4e0fdfce8ffffedfbfae6f5f4e0ffffecf9f8e4f5f4dfffffedffffecffffedffffec +f9f8e4fbfae5f0efdbffffecffffedfffee9e6e5d1ffffedf5f4e0fbfae6f1f0dcffffed +f7f6e2ffffebffffedfcfbe7fffeeafffeeaf4f3dfffffedffffedeae9d5faf9e5fefde9 +ffffecf5f4e0fdfce8fcfbe7fefde9ffffedffffedf5f4e0faf9e5ffffedfaf9e5f1f0dc +ffffedffffedfbfae6ffffedffffedf9f8e3ffffedffffecffffedfefde8ffffebfdfce7 +faf9e5ffffecf3f2deffffeceeedd9ffffecffffedffffecfdffe7feffeafcfee9feffef +010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffbfffffbfefdf9 +fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfecece0 +eeeee6ecebe7ede8e2f4edddf4eac7ffefb3af9d47fffa8dffeb73fff37bfffc8cfff492 +fff9a5fbfbb3dbe7b590ad99a4c8c49fc0b7bad8ce9db2abdcede7ced8d7ecf2f2fafeff +fcfffbeff5ebeef6e7d2ddccedfbeaf5fff8fcffead0cc8d7d742993874bf8eebdebe1be +eae2cbf4ecdffaf3e9efebe2eeece0eeece0eeecdfeeecdfefebe0efebe2efebe0efebe0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecdfebecdcedefe1eceee1e9ece1ebf0eae6ebe7ecedef98979ceee7ef +fffaff897580fff5ffa7838fffedf74d1d2967465bfaf8ff06124297a3cb1c2745dce7f9 +030e14f9ffff474f44fafff2f3f7e9fffff8030400f5f4f9fffdfffffcff01000cfffeff +010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7fbfde8f3f4e2fffff3fffff1eeefdf +fbfde8ffffecf3f5dfeaecd7ffffedf6f8e3feffebffffedf4f6e0ffffecffffecf9fbe5 +ffffeaffffeaf8fae2fdffe7eceed6ffffeaffffeaffffeaf7f6e1f5f4dfffffecffffec +fcfbe6f0efdaffffecffffecffffecffffecfffee9fdfce7ffffecfdfce7ffffecfdffea +eff1dcfeffebfeffebf5f7e2ffffecffffedf7f9e4edefdaffffedf5f7e2fafce7ffffed +e8ead5ffffedeff1dcf7f8e6fdfeecffffefe4e5d3ffffefffffeffdffeaeceed9ffffed +f8fae5fcfee8f2f4def4f6e0ffffebffffeaffffeaffffecfdfce8f8f7e3ffffedfcfbe7 +ffffedebead6060500ffffedfaf9e5f9f8e4fefde9ffffedf6f5e1ffffedffffedffffeb +f8f7e3ffffebfffeeaffffedfaf9e5ffffed050400f4f3dfffffecf8f7e3ffffedffffec +ffffedfbfae6fcfbe6ffffebf6f6deffffecffffeafffee9f3f3dbffffeafcfce4fbfae5 +ffffeaffffecf7f7dfffffecf6f6deffffecfcfbe6ffffebfffeeaffffedf9f8e4ffffec +fcfbe7fcfbe7fffeeaffffecfefde9f5f4e0ffffebf1f0dcffffedffffedfdfce8f3f2de +ffffedfdfce8ffffedfdfce8f6f5e1f5f4e0ffffedf6f5e1fffeeaffffebffffebefeeda +fcfbe7f5f4e0ffffecffffecf2f2daffffecffffe9fefde8fafae2fcfbe6ffffe7ffffec +fafae2f7f6e1ffffeaffffecf2f2dafefde8f3f3dbfdffe7feffeafcfee9feffef010100 +908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffbfffffbfefdf9fffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfebede0edeee6 +ecebe7ede8e4f4edddf6e9c6ffefafb29d44fff182fcdf67ffe36effee80ffe989f7e78f +f0e897e1e09de0e5bcadb89aacbca1a1b6a3d9f0ead9f4fdd3eeffc0dafbd5edffd6ecff +d3e4ecd2ddd7dcded0fffae7fffdedfeefd0aba0628c823ae2d69cfff4c6f2e7c9ebe3d0 +f5ece3f3ece6efeae4eeebe4eeece0eceddfeceddfeeecdfeeecdfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeecdfebecdeedefe1eceee1e9ece3ebf0e9e6ebe7ecedef98989afffdfffcf1f7 +918086fff7fd88696fffecf0fff2f83e2425fafffbf1ffff3f534a384941e8f7f0000500 +f9fffb535a53fcfffbfcfefbfffffd000000fefcfffefcfffffeff010002fffffd010100 +fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7f9fbe6ffffeff5f6e8f2f3e3fffff1f3f5e0 +ffffecf9fbe3fbfde7ffffece8ead4ffffecf7f9e3f9fbe5edefd9ffffeaffffeaf0f2da +fafce4ffffe8fafde2ffffe8ecefd4ffffe8f5f5ddffffeaffffeaf6f6deffffe7f8f8e0 +ffffeaf2f2daf9f9e1fcfce4f4f4dcffffeaf2f2daffffeafcfce4ffffeaffffecfdffe9 +feffeaffffecf6f8e2eff1dbffffecffffebf1f3ddffffecf1f3ddffffebffffecffffec +f3f5dfffffedfeffedf1f2e0ffffeffeffedffffeffeffedf2f4dfffffedf3f5e0ffffed +f9fbe5ffffecf8fae4ffffecfdffe7f8fae2ffffecfffee9f7f6e1ffffecffffecf6f5e0 +ffffecf5f4dfffffecf9f8e3ffffecf9f8e3f2f1dcffffecf2f1dcf6f5e0ffffecf8f7e2 +ffffecfdfce7fffee9ffffecf3f2ddffffecffffece5e4cfffffecffffecf5f4dfffffec +ffffecfcfbe6ffffeaffffe5fefee6dedec4ffffeaffffe8ffffeafefee4ffffeaffffe7 +f6f6deffffe8fefee6ffffe8f8f8e0fafae2ffffecf8f7e2faf9e4ffffecfbfae5ebead5 +ffffeceeedd8fcfbe6ffffecffffecfefde8ffffecffffebeae9d4fffee9ffffecedecd7 +ffffecfaf9e4fffee9ffffecf2f1dcffffecffffecfefde8fefde8f5f4dfffffecffffec +ffffecf1f0dbf8f8e0ffffe8fafae2efefd5fefee6ffffe8ffffeaffffe8ffffeaf9f9df +ffffe8ffffe8e2e2caffffe5ffffeaffffeafdffe7feffeafcfee9feffef010100908f8a +aaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffbfffffbfefdf9fffffdffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfebeddfecf0e2ecebe7 +ece9e4f5ecddf7e9c6ffefadb49c42ffeb7dffe975ffdf73f9d773f6d87ee8d27cd1c26d +c0b86fc8c494c0c09ee0e7c6edfce7e4faf7c2ddeeaccaf0b9daffc7e4ffc4def9d2e5e9 +ccd9c8f4f4d8fffedefff7dcddc7a282733a887d3ffef2c0f3e7c1fff5dff7ede1f5ebe9 +ede8e5eeeae7eeebe6ecece2eceddfecedddeceddbeeeddbeeecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfedebdeeeefe1edede3eaebe3edf0e9e6ebe7eaeeed97989af7f5f8fffdff857b7c +fffafb978183ffeae9f2d4d2f3e1d5e0ebcdcae2bedcf1d2eeffe7ccddca0e1c0ff1fcf4 +4a5350f4f8fbfcffffeff0f4020204fffefffffffdfdfcf7020100fffffb010100fdfdf1 +ffffeff9fbe3ffffe8fdffe5fdffe7ffffedf5f6e4fffff2fffff1fafbebffffedebedd7 +ffffeaffffecf7f9e3ffffecffffecf7f9e3ffffecf8fae2ffffeafbfde5ffffeafcffe4 +ffffe8eff2d7ffffe8ffffe6f3f6d9ffffeafbfbe3fbfbe3ffffeaf1f1d9ffffeaf7f7df +ffffeaffffe7ffffeafcfce4fdfde5ffffeaf8f8e0ffffeaf8f8e0ffffecf9fbe5ffffec +f0f2dcfcfee8ffffecf0f2dcffffecffffecf9fbe5ffffecffffece6e8d2ffffecfeffea +f6f8e2fbfceaffffefebecdaffffeffbfceafafbe9ffffedf4f6e1f4f6e1ffffedf7f9e3 +f3f5dfffffecf4f6e0f3f5ddffffeafffee9f9f8e3ffffecffffecf0efdaffffecf0efda +ffffecfbfae5ffffecf9f8e3ffffecffffecf4f3deffffecffffecffffecffffebfbfae5 +ffffecf6f5e0ffffebffffecfbfae5f5f4dfffffecfcfbe6efeed9ffffecf6f5e0fdfce7 +ffffe8f9f9dffafae0ffffe8ffffe8f8f8defdfde3f3f3d9ffffe8fefee4fdfde3ffffe8 +ffffe8f9f9dfffffe7fbfbe1ffffe8f8f8e0ffffecfdfce7fbfae5f8f7e2ffffece7e6d1 +ffffecfaf9e4ffffecf6f5e0fdfce7ffffebffffecf3f2ddffffecfaf9e4ffffecfffee9 +fbfae5ffffebfdfce7ffffebfaf9e4ffffeaf6f5e0ffffecffffeaf9f8e3fdfce7fcfbe6 +ffffe8fdfde3ffffe8fafae0ffffe8f7f7ddffffe6ffffe7f9f9dffdfde3fdfde3fafae0 +ffffe8ffffe8fdfde3ffffe6f9f9dffdffe7feffeafcfee9feffef010100908f8aaaa9a7 +d8d6d7f8f6f9fefcfffffefffffefffffefffffffbfffffbfefdf9fffffdffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddebeed9ecf0dfecebe6ece9e4 +f5ebdff7e9c6ffefadb59c42f5d66cffdf71ffdc7ce4bf67e5c475ffe699fff2a0ffffbf +fffedbfafde8f0f8e1dfecdacddddac4d7e5c6dbfacce3ffcde1fccbdee5c2d4bccedbaf +fbffc8ffffcdffffd4aa9d717a6e3cf7eabdfff3d0f1e5cdfbefe3eee4e2f4ebeeebe5e9 +eeeae9ecebe6ecece2ecedddeeeddbeeedd9eeedd9eeeddbefecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeeadef1ede1efece3ebebe3edf0e9e6ebe7eaeeed95999afcfffff8faf98c8b89fffffa +0600000f06000f0200070200000b00122300011100000700051302000b03f9ffff495154 +f2f5fcfcfffff6f7fc0000020a0907050400030000fffff6fffffa010100fdfdf1ffffef +f9fbe3ffffe8fdffe5fdffe7ffffedeceddbfffff3fffff0f8f9e9f9fbe6ffffecf8fae2 +fdffe9f7f9e3ffffecf1f3ddffffecfdffe9f7f9e1ffffeaffffeaf8fae2fafde2ffffe8 +f7fadfffffe8fcffe2ffffe6f9f9e1ffffeafcfce4f8f8e0ffffeaffffe9ffffe9fefee6 +f7f7dfffffeafdfde5ffffeaffffe9ffffeaf3f3dbfcfce4ffffece7e9d3ffffecfdffe9 +ffffebfeffeaebedd7ffffecffffeceff1dbffffeceff1dbf9fbe5ffffecffffebf8fae4 +ffffefffffefeeefddffffefffffefffffefeceed9ffffedfdffeafdffeafdffe9fdffe9 +fdffe9fdffe9fdffe7fdffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe5ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe5ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe5ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe5fdffe7feffeafcfee9feffef010100908f8aaaa9a7d8d6d7 +f8f6f9fefcfffffefffffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc7 +0837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeeddbebefd8edf0dbecebe6ede8e4f5ebdf +f7e8c7ffefabb59c42ffe67ffcd76ff6cd75ecc276ffe4a0fff6b0ffffadfffbb2fffac9 +fffdd7fafcd4e7f1cecfe0cdc2d6d5c0d6ebc3ddf6bdd7e4bbd2c8d7edbfe7f6b1ffffb6 +fdf7a9e1d1939b8a56a09168f1e4c4f0e4ceefe3d5f9eeecece1e5f4edf4f0ebf1eceaeb +ecebe6ecece0ecedddeeedd9eeedd8eeedd8efecd9efecddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0eade +f3ede1f0ece3ebebe3eeefe9e8eae7e9efed949a9af9fffff6fffc7a807cfcfffafcfff8 +fefff6fffff3fbffeef7feece6efdefbfff6f9fffaf5fef9f1faf9f9ffff4a4f55fcffff +f3f6fdfeffffeaebedfbfbf9fefdf8fffff6fffff6fffffa010100fdfdf1ffffeff9fbe3 +ffffe8fdffe5fdffe7f8fae5090a000102000102000d0e00fcfee9020400ffffeaffffec +f6f8e2ffffecf4f6e0f8fae4ffffecf7f9e3f5f7dff9fbe3ffffeafcfee6ffffe8feffe6 +e8ebd0ffffe8ecefd4ffffe9ffffe8ffffeaffffea030300ffffeaf2f2daffffe8ffffea +fafae2ffffeaf7f7dfffffea0303000c0c00090900f6f8e2ffffecf2f4de050700010300 +090b00ffffecf1f3ddfafce6ffffebf9fbe50e1000010300ffffeceaecd6ffffed010200 +030400ffffef0c0d000102000102000f1100edefdafdffeafdffeafdffe9fdffe9fdffe9 +fdffe9fdffe7fdffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe5ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe5fdffe7feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9 +fefcfffffefffffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db +1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeeddbecefd4edf1daecebe6ede8e5f5ebe1f7e8c7 +ffefabb59c40ffe581efc968e5ba6cf6cd8bfff8bcfff8b5ffffaefff39bfff49dfffba5 +ffffa9f3faadd6eab5bedcc4b0d7dcadd9e6aad6d9b7dfc7e6ffc7daed93ffff9effff9a +d0ac58896527e5d1aef9eedcede0d7f5eae6f9eef2eae0e8f3ecf4eee9efecebe9ecece4 +eeecdfeeeddbefecd9efedd8efecd9efecdbefecddefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdff1e9def4ece1 +f0ece3edeae3efeeeae8eae7e9efed929b9af1fbfaf7ffff808d86bfccc3c0cdc3d0decf +b2bfaec5cfc7e3e3efd2cfe4c1bed1cfcee0cdcfdccbcdd9c8cbd454575ef2f5faf4f8fb +f6f7f9fefffffffffff7f7f5fffffdf6f5f3fffffb010100fdfdf1ffffeff9fbe3ffffe8 +fdffe5fdffe7010300f1f2e0fffff3fffff1e7e8d8ffffede9ebd5f8fae4fdffeaffffed +eaecd7ffffedf9fbe6fbfde7fcfee8ffffecfeffeaeff1d9ffffeaf6f8e0ffffeafcfee6 +f4f6deffffeaffffe7ffffeafdfce7030200030200f9f8e3ffffecfefde8fefde8ffffec +ffffeafefde8060500f9f8e3fffee9fcfbe6020400f0f2dd121400f6f8e3ffffedeff1dc +010300feffebffffedeceed9ffffed010300080a00f5f7e2fcfee9eef0db010200030400 +fafbe9010200ffffeffdfeecf8fae5060800fdffeafdffeafdffe9fdffe9fdffe9fdffe9 +fdffe7fdffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5fdffe7feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcff +fffefffffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff3 +1e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeeddbecefd2eef0d8eeebe6efe6e7f7eae1f7e8c7ffefaa +b59c3ffbdb74e7c363deb46affe3a5fff2b8ffedaafff69dfff991fff587fff985ffff89 +fcff92e6f5a0cee7aeb9d9c2afd3c9bee1cdcdeec1f1ffb7d2df75ffff92ffef87b18a3b +ad8551fff2d7fbf1e7ede4ddf8eeedf6edf2eae3eaf4eff3e9e5e6ecebe6ecece0eeecdd +efecd9efecd9f1ecd9f2eaddf1ebddefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdff1e9def4ece1f0ece1 +edeae3efeeeae8eae9e9efef929b9af7fffff5ffff4c5b5652615a415146516154556656 +49524d433e525c516f5c526d4b435a524e5f504e5b58586046474cfcfffffcfffffeffff +f9fbfaffffffffffffeeeceffffefffffffd010100fdfdf1ffffeff9fbe3ffffe8fdffe5 +fdffe7060800f0f1dffbfceefffff1feffefedefda151701fafce6010300010200121301 +010300fdfeecf9fbe6020400040600010300ffffecf7f9e3fcfee6010300ffffe9ffffea +eceed8f9f8e3fcfbe6ffffedfefde80b0a00fefde8fbfae6ffffecffffedefeed9fdfce8 +ffffec030200ffffeaffffedfffeea050700fbfde8feffedffffede9ead8ffffed030400 +ffffedf8f9e7ffffedf3f4e2030500fbfcea010300ffffef0f1000fcfdeb101100f8f9e7 +0c0d00fafbe9fbfceaffffed010300fdffeafdffeafdffe9fdffe9fdffe9fdffe9fdffe7 +fdffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5fdffe7feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffeff +fffefffffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bc +e2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeeddbecefd2eef0daeeeae7efe6e9f7eae2f7e8c7fff0a8b49d3d +fade73e9c765e1bb70fff9b9ffecadfff2a6f5f08affff8efffa82fffa7cfdfe74fdff79 +f9fe88edf294dcde9fced09ee9eab1ebeda2fcff96edec76ffff96bfad57876b3bf2d8bf +f4e7d6ece6dae9e5dcf0ebe7ebe7e6eeeae9f6f5f1e6e6deeeecdfeeeddbefecd9efecd9 +f2ebdbf2eadff3e8e2f2e9e2f1eae0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0eadcf1ede1f0ece1edeae3 +efeeeae8eae9eaeeef929a9cf9ffffedf7f8ebf5f4f8ffffe7f2eceffaf2effbf1fcfffb +fffbffeddde8fffafffffbfffffcfffdf8fcfdfbfefafafafbfdfcf0f2f1fcfdfffeffff +f8f8fafffefffbf9fefffefffffffd010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7 +eff1dc20210f010200010200f0f1e1ffffed060800f8fae4feffedf5f6e6eeefdf0a0b00 +fdfeee0b0c00ffffeffbfde8ffffed010300fbfde8ffffec0a0c00f1f3ddffffecffffec +ffffedffffedfdfceafcfbe7030200f7f6e2ffffeff5f4e0ffffefffffedffffeffaf9e5 +060500ffffedffffeef5f4e2010200fcfdebfffff0f6f7e5fffff1030400edeedefbfcea +fffff1f8f9e7f8f9e9090a00fffff1080900eaebdb050600fbfcea040500f7f8e6020300 +010200010200010300fdffeafdffeafdffeafdffe9fdffe9fdffe9fdffe9fdffe7fdffe7 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +fdffe7feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffeff +fffefffffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8ff +f4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecdbeeeed4f0efdbefe9ebefe5edf7eae4f7e8c7fff0a6b29f39ffe577 +e0c35de9c879fff8b5ffe8a4fffda9eded7bf8fc81fafa88f8f781f8f971fefd71fffe7e +fff68af6e492edd690ffea9efff495fff378f3e868f7ea7aa392409e8662ffeee0ebe4d2 +eae8d9efede0edede3e8e8e0eeeee4f1f1e5e6e7d7eeedd9eeedd8efedd8f1ecd9f3e9df +f5e8e2f5e7e7f3e7e7f1eae2efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfedebdcf0eee1edede1ebebe3eeefea +e8eae9eaeeef95999cf7fcfffbfffffbffffecf0f1fcffff0f14100002000101000a0000 +1f10000d00000a0000080000fffef4fefbf4fffffbfffffffefffff9fafefeffffebeaef +f3f3f5fffefffffefffffffd010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7ffffed +fdfeecf7f8eafffff10a0b00f4f6e1040600f3f5dffcfdebfffff1080900fafbebf9faea +040500010200070800010200020400f7f9e4feffebffffecf5f7e1fbfde7f6f8e3ffffef +ebead8ffffeffcfbe91c1b09f0efddffffefffffeffcfbe9efeedcffffeff6f5e3030200 +ffffefffffeeffffef010200fffff1fffff1f2f3e3010200fbfcecf6f7e7fffff1f8f9e9 +feffeffffff0030400e6e7d7fffff1030400f9faeafbfcea010200ffffef010200ffffef +ffffefffffed010300fdffeafdffeafdffe9fdffe9fdffe9fdffe9fdffe7fdffe7ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7fdffe7 +feffeafcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffeff +fffffbfffffbfefdf9fffffdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2 +e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecdbeeeed6f0efddefe8efefe5eef7e9e6f7e8c7fff1a4b29f38f8e16fd2b74c +ffe491ffeca3fbea9cfffb9be8ef6eeff877f6f392f7f095fcf281fff47afff480fff08a +ffe797ffe197ffe591fff78dffec66efdc51ccb940a38f36e5cca4f0ddccf6f0daeef0da +f2f4dfeef1deebeeddeaeddae6e9d4ebedd5eeeed4eeeed4efedd6f1ecd9f3e9e0f5e7e7 +f6e5edf5e6edf1eae4efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecdfebecdcedefe1eceee1eaebe3edefeae8eae9 +ecedf197989dfffefffffefff4f3f9fffefffffdff030000fffdfdffffe6fffbb2fff99c +fbf3a2ffffc10a0400161100fcf9e8fdfcf7faf9fefffdffeaeaf4fefefffffefffffffd +fffffaf8f9f3fffffb010100fdfdf1ffffeff9fbe3ffffe8fdffe5fdffe7f5f7e2ffffef +fffff3ebecdc080900feffeb010300feffeaf9faea010200f4f5e7f8f9ebfffff3010200 +f1f2e2fffff1fcfdedffffefffffefffffefffffeffafce7ffffedfeffebf8f7e5fffff1 +fffff1f4f2e3030100fffff1fdfbecefeddefffff1fffff1fcfaebfffff1030100fffff1 +f8f6e7f7f5e6020300fffff3f9faec010200fffff3fffff3fffff3f8f9ebfffff3f9faec +f4f5e7080900f5f6e8fffff3020300fffff0ffffef080900e4e5d3080900f8f9e7eaebd9 +ffffed020400fdffeafdffeafdffe9fdffe9fdffe9fdffe9fdffe7fdffe7ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe7fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9ffffe7ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe7fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fdffe7feffea +fcfee9feffef010100908f8aaaa9a7d8d6d7f8f6f9fefcfffffefffffefffffefffffffb +fffffbfefdf9fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eada +ebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecddeeedd9f0eedfeeeaebefe6e9f5ebe2f6e9c7fff1aaaf9f3feed86bc9b147ffffa6 +ffe994ffed94fdf088f3f06ffdf97cfbec91ffec96ffef88ffee7effeb7cffe881ffe890 +ffea97ffe68affea80ffe96bffea6ba8962a867324fff8d1feedd9f3eed8e7e9d3e8ead4 +e9ecd7eef0dbe7ead5e2e4cef6f8e0eeeed4eeeed4efedd6f1ebdbf2e9e0f3e8e6f5e6eb +f3e7ebf1eae2efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeceddfe9eddeeaf1e1edeee0edebdfefefe7e9eae5e9efef +94999dfaf8fffcfeff00050f000c11000d0c000f0e000007fffde8fffca7fff280ffff9a +f9ee9c080500ffffe2080800fdfdfbf7fbfafefffffffcfffffcfff4f8ffeff7f9fcfef1 +fffff1fffff8010000fffcf3fffff1fbfae6ffffecffffe7fdffe9ffffedf8f9e7f5f3e4 +fffff1030200ffffed030200feffeb060400fcfdeffffff2fffff3efede0030400fffff1 +fafbebfffff1010200ffffeff2f3e1060500ffffeffaf9e7fffeecffffeffcfbe9f4f2e3 +ffffef0b0900e9e8d6fffff1ffffeffefced070600f2f0e1ffffee030100fdfceafffff1 +fffff1030100fffff10d0b00f9faeafffff1f9faeafffff1f6f7e7fffff1fbfcecfbf9ea +070800fffff0fafbebfffff1fafbebf5f4e2050600ffffef010200ffffedffffeff6f5e1 +080a00fffeeafdffeafffee9fdffe9fffee9fdffe9fffee9ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fdffe7feffe8fcfee9 +feffef010100908f8aaaa9a7d8d6d9f8f6f9fefcfffffefffffefffffefffffffdfffffb +fefdf9fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dc +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfecedddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +f3f6e5e1e4d3f2f0e4f5f1e5e8e2ccfff8d4f5e9ada69649f5e085dbc35ffff995ffe47e +fedf75ffe97bffe671ffe977ffe27effdf7effea7ffedd6cffed7cffe677ffec82fbe079 +f0d773d8c161c8b556b1a14a8e7f3af1e1aefff0d1ebdfc9f1ecd9eeeddbeeeddbeceddb +eeeddbeceddbeeeddbeeeddbeeedd9eeedd9eeeddbefecddefebdfefebe0f1eae2f1eae2 +efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfebeddfe4efdee9f2e1f3ecdcf5e7daf6eddeeaeadee2f3e98b9d9f +fbfcfff1ffff00102064cccf0391835dd1c8000a1b614446674a0effffa6ffea94fff6b2 +0b0b00fafff9f7faff000107f4fff3f9fff1ffebf6fff7ffecfafff0fffffbfde8ffffe4 +fffef4030000fffaf6fffff6fdf9edfffff1fbf8e7f8f7e50b0800030200171403030200 +f8f5e2fefde9040100ffffef0401000a0800040100171506f6f3e4fefced060300030100 +040100fffdeefffff0fffff0040100fffdeefffff0ffffeffaf7e6fffce9ffffef040100 +0906000c0900e9e6d5ffffedfffdec040100f7f4e3ffffedf3f0df040100120f00040100 +ffffeff8f7e5110e000302000401000e0d00040100fffeecfefbeaffffeffefbea030200 +ffffefffffefefecdbffffeff3f0dd181703fbf8e5030200100d00030200040100ffffed +fffdeafffeeafffdeafffeeafffdeafffeeafffdeafffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffdeafffdeafffdeafffdeafffdeafffdeafffdeafffdea +fffdeafffdeafffdeafffdeafffdeafffdeafffdeafffdeafffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffdeafffdeafffdeafffdeafffdeafffdeafffdeafffdea +fffdeafffdeafffdeafffdeafffdeafffdeafffdeafffee9fdffe7fdffe8fbfee9fdffef +0002008f908aa9a9a9d7d7d9f7f6fbfdfcfffffefffffefffffffffffffdfffffbfdfef9 +fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfecedddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddecedddeceee0 +e2e4d6eeefdff0eed9e6e0c6faf2cdf4e8b6bfb06fd7c475f3dc7ffff995fbdc72ffdf73 +ffe479f9d368ffdc76ffdf7dffd979ffdd7afcd973f3d46ad3b74cbea63cb09a34a39334 +92832e91853d82763cfff9ccf4e9c9fff7def0e8d5efecdbeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfebeddfe2f0dfe7f2e1f4ebdcf8e6d8f9ecdceaebdbdff5e8899f9dfbfdff +dcf0ff001b2a0381803bebd7008476000619fff3f8fff7c2ecc776fffbadffefb2070200 +000300151723000105000700f1fbe3fffbfdfffaffebfafff1fffff5f4dfffffe3fffbf1 +191410fffefafdf9f0f8f4e9fdf9edfffff0ffffeff7f4e1f1efdafbf9e4fffde8ffffec +ffffecfffce9fffce9fffeedf1eeddffffeff8f5e4f8f5e4ffffeff2efdeffffefffffef +f2efdefefbeaffffeff2efdef9f6e5ffffeff2efdeffffedffffecffffebfbf9e4ffffec +ffffeafffde8f6f4dfffffecf9f7e2ffffecfdfbe6f9f7e2ffffecf2f0dbffffecf8f6e1 +fffde8fbf9e4ffffecf7f5e0fffde8fbf9e4ffffecffffebf3f1dcffffecfbf9e4fefce7 +ffffecf9f7e2ffffecffffecfefce7fefce7f7f5e0fffee9fdfbe6faf8e3f7f5e0fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9fffee9 +fffee9fffee9fffee9fffee9fffee9fffee9fffee9fdffe7fdffe8fbfee9fdffef000200 +8f908aa9a9a9d7d7d9f7f6fcfdfcfffffefffffefffffffffffffdfffffdfdfef9ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfecedddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddecedddebeddfebeddf +f1f2e2f0eddaece6cef7eecdf9eec0e8d99ebaa961ffffadf6dd80fbdf7cffe986f1cf6d +ffe686f9d479dbb864dab968c5a653aa8e3a8e741d8f7a218e7d2591822f85782afff8b3 +eae1a8efe7b9e6e0bef1ebd3e3dccafffceeefecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfebede0e3efe1e7f2e4f3ebe0f5e7daf9ebdeeceadbe0f4e88a9e9cfcfefff4ffff +00101b6fd1d000907962d7c400070efff7effff7b7fffea67a4000fff6bceddaafffffe8 +f4f4eafffffb141007f7f7edf8fffaf2fffaecf7f3f8faf5ffffeffdf4e3f3efe4060300 +f0ede4fffff3fffff1fcfbe9f5f4e0ffffecffffeaffffeaffffe8fdfde3fdfde5f7f7df +ffffebffffebffffecfbfae5fcfbe6ffffecfefde8fffee9ffffecfcfbe6ffffecffffec +fcfbe6ffffecf7f6e1ffffecffffecffffecfdfde5fdfde5f7f7dfffffeafbfbe3ffffe9 +fefee6ffffeaf0f0d8ffffeaeaead2ffffe9fcfce4ffffeaf9f9e1ffffeaffffeaf8f8e0 +ffffeafdfde5ffffe8fcfce4ffffeaf8f8e0ffffeaffffeaf8f8e0ffffeaeaead2fafae2 +ffffe9ffffe9fbfbe3fefee6ffffeaffffeafcfce4ffffeaffffe8ffffeaffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7 +ffffe7ffffe7ffffe7ffffe7ffffe7ffffe7fdffe7fdffe8fbfee9fdffef0002008f908a +a9a9a9d7d7d9f7f6fcfdfcfffffefffffefffffffffffffdfffffdfdfef9ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfecedddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddebecdef1f2e4f1efe0 +efecdbf3edd7f6edd0f9edc5fff3bfaa9b5af1df95ecd784e0c870ddc26bddbf69b2923f +aa8a3d977c39a08848846c2c7e69289d8a48f3e4a1fff7b6f0e6a8f6edb4faf4c2ebe6be +ffffe1f9f7e0efeddeeae8dce5e2d9eeecdfeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +ebede0e4eee3e7f1e6f2ebe1f4e8dcf8ece0eceadde3f3e68b9e98fefeffe9f1fe001721 +276c6966d1bd227b67000907ffecdefbf0b8ffffb6624600fffcb2f9ffc1edffcfedffe3 +e6fae1010000fffdfdf5fcf5f8fffaf7f8f0fffff8fffaf4fffef8fffff60a0800f9f7ea +fffdeeffffeefefde9f7f7dfffffe8ffffe8e6e6caf5f5d9f8f8dcffffe8ffffe8f0f0d8 +ffffeaf3f3dbffffeaeeeed6f7f7dfffffeaffffe8f8f8e0f6f6def4f4dcffffe9fcfce4 +ffffe9f5f5ddfdfde5f9f9e1ffffe8f8f8deffffe8ffffe8f7f7ddffffe8ffffe6ffffe8 +f5f5dbffffe8fbfbe1fefee4ffffe8ffffe8f6f6dcffffe8ededd3fefee4ffffe7f0f0d6 +fefee4ffffe8fdfde3e7e7cdffffe8f3f3d9ffffe8fafae0ebebd1ffffe8ffffe7ffffe8 +f4f4daffffe8f6f6dcfbfbe1fbfbe1ffffe8e9e9cffafae0ffffe8ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5fdffe5fdffe7fdffeafbfeebfdfff10002008f908aa9a9a9 +d7d7d9f7f6fcfdfcfffffefffffffffffffffffffffffffdfdfdfbffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddfecedddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdde8e9d9edeedeeae8dbeae7d8 +f5eedcf1e9d2f1e6c6fef2c8b0a36ed7c789af9c57ad9950846e257c641c9e834091793d +8d7b49ddcfa2fffacdfff8cce7dcaffff7ccfcf4cdefeac4fffadad0ccaff9f7e0e6e5d3 +ebebdfd8d9d1f6f7f2eeefe9ecece0eeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfecece0 +e6ede5e9f0e8f0ece3f1e8dff6ece2eceadee5f3e68d9e96fafdfffcffff00030b001211 +002111001300000400fffff4f4ffefebffe1e7ffc83b821a08770011890d036b0c00440a +001000fffdffffebfcfff4ff09030700010206060ee5e6eaf9f8f3030100fffff1fdfcea +ecebd7ffffecffffe7fefee2fafadeffffe4ffffe1ffffe4fbfbdff7f7dbffffe8f3f3d9 +ffffe8ffffe8ffffe8ffffe7f0f0d6f4f4daffffe8ffffe8ffffe8ffffe8fcfce2f6f6dc +ffffe8ffffe8fafae0f7f7ddffffe8fefee2ebebcfffffe4f4f4d8ffffe6f9f9ddffffe6 +fcfce0ffffe6f8f8dcf5f5d9f6f6daffffe6ffffe6ffffe6fbfbdfffffe3f5f5d9ffffe5 +ebebcfffffe6ffffe6ffffe6fdfde1fafadeffffe5ffffe6ffffe3ffffe5fdfde1ffffe4 +f0f0d4ffffe6ececd0ffffe6ffffe6ffffe6ffffe6efefd3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3ffffe3 +ffffe3ffffe3ffffe3fdffe5fdffe9fdffebfbfeedfdfff20001008f908ba9a9a9d7d7d9 +f7f6fcfdfcfffffefffffffffffffffffffffffffdfdfdfbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc7 +0837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfecedddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddedebdcefeddeebe7dbebe7dbf5efe1 +f2ebd8f0e6cdf7edcaefe3b98e814d83743b817136a7945afff1b9ffe9b7f8e6b8f8ebc8 +f7f1d1f0e7caebe4c8e7e1c7f6f2d9f6f1ddf3f0ddf0eedff5f6e8f1f1e7e4e5dddbdcd6 +fefffbe1e3e0e4e7e0ecece0eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0e9ece3 +ecefe8f0ebe5f1e8e1f5ece3ece9e0e5f2e88d9e96f7fcfffffeff090810000205e8ffff +001203000a00eefcefdffff7236e43147a2736b1463dcc560ca234007f2d076f3e000c04 +fcf4ffffe9fe18000cfffbfffbfefff5f8fffcfffffffffb030100fefcedffffefffffeb +ffffecf9f9e1fbfbe1ececd0ffffe6f9f9ddf2f2d6ffffe8fefee4fbfbe3ffffeaffffe9 +e7e7cffbfbe3fefee6fcfce4ffffeaffffeaf6f6dee9e9d1ffffeafbfbe3ffffeaededd5 +ffffeafdfde5ffffeaf8f8deffffe5fafae0ffffe8ffffe6ffffe8f8f8deffffe8fefee4 +fcfce2ffffe8ffffe7ffffe8ffffe6e6e6ccffffe8fefee4fdfde3ffffe8ffffe8fafae0 +fefee4ffffe8f0f0d6ffffe8f1f1d7ffffe8ffffe8efefd5fbfbe1fbfbe1ffffe8ffffe6 +fdfde3ffffe8fdfde3e9e9cfffffe8f6f6dcffffe8ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5ffffe5 +ffffe5ffffe5fdffe7fcffeafdffedfbfdeffdfff20001008f908ba9a9a9d7d7d9f7f6fb +fdfcfffffefffffefffffffffffffffffffffdfdfbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db +1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeceddfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecddf0eedff1eedff0ece0efebe0f2ebe1f4ecdf +f3ecd9f2ebd1fff7d6f1e8c1fcf1c4fbeec2ebdeb2eedfb6fffad6f9ecccefe9cfeae8d3 +f6f1def6f3e2f8f4e8e8e6dae7e4dde6e5e0e6e5e1e9eae5e5e6e1ebece7fcfdf8e3e6df +d5d8d1fbfcf4ecece0eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0ebebe1f0ede6 +f2ebe3f1e8e1f5ece5eaeae2e5f2e98b9e98f7fffff5f6fb0d010dfff8ff070b0eeaf6f2 +06170fe0ffed276c4083e9a744cd750d9b4909824f006f5600807800414800061cfff8ff +fff9ff070005fcf6fffffdfffdfcfff2f2faf1f0ec1b1b11f7f7ebfffff2fffff1f0f1df +f8fae5ffffecffffeceef0dafdffe9fcfee8fdffeaffffedf0f1dfffffeeffffedffffed +ffffedf8fae5ffffedffffedf1f3defdffeaffffedf3f5e0fbfde8ffffedffffedf1f3de +f8fae5ffffedffffecffffecfafce6e6e8d2fafce6ffffecffffecf4f6e0fbfde7f8fae4 +ffffecf2f4def5f7e1ffffecffffecf7f9e3ffffecfdffe9f6f8e2f3f5dfffffecf3f5df +f9fbe5ffffecfbfde7ffffecffffecf0f2dcffffecffffecfdffe9f2f4deffffecf4f6e0 +f4f6e0f9fbe5ffffecfcfee8fbfde7f7f9e3fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9 +fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9 +fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9 +fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9 +fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9 +fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9 +fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9 +fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9 +fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9fdffe9 +fdffe9fdffeafcffecfdffeffbfdeffdfff40001008f908ba9a9a9d7d7d9f7f6fbfdfcff +fffefffffefffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff3 +1e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddfeceddfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeebdaedead9f0ece0ede9dee9e2daeee7dff4ece1 +ede6d4f3ebd4eae3c6fff7d6f0e7c6f7eccef8ecd2fff5ddeee6d1f1eedbefeedcf6f4e7 +e5e3d7f0f0e8eae9e4f4f3f1eceaebe3e1e2fcfafbebeae8e6e5e1ecece4e8e8def8faed +eaeadeeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeadef3ece2f3eae1 +f2e7e1f5ece7eae9e5e3f2eb8a9f9af2fffff9feff080009200b1cfff3ff000007000807 +2b654d8defb643c67a009144007e45003a2e67e9f93ad1ec61d8f6000723fef6fff6f7fc +000004fffcfffaf6fffdfdfffeffff0c0c0a010000fdfdf5fafaf0fffff4f1f2e4fffff1 +f7f8e8f9faeafafbebfffff1fbfcecfefff1fefff1f4f4e8fffff3f8f9ebfcfdeff9faec +fefff1fffff2fcfdeffffff3fefff1fffff3f9faecfffff3f9faecfffff2fcfdeffffff3 +f8f9ebf0f1e1fcfdedfffff1fffff1fcfdedfafbebf9faeafdfeeefafbebfffff1eff0e0 +fffff1f8f9e9fffff0f8f9e9fcfdedf6f7e7fafbebf7f8e8fffff1fdfeeefffff1f7f8e8 +f8f9e9f9faeafffff1f1f2e2fffff1f0f1e1feffeffdfeeefffff0f8f9e9f6f7e7fffff1 +fffff0f6f7e7fcfdedf4f5e5fffff1fdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeee +fdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeee +fdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeee +fdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeee +fdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeee +fdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeee +fdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeee +fdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeee +fdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeeefdfeee +fdfeeefcfef0fdfff1fbfdf0fdfff40001008f908ba9a9a9d7d7d7f7f7f9fdfcfffffeff +fffefffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bc +e2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +eaeadee7e5d9f1efe3f6f4e8efede1eeece0efede1edebdff9f7ebf4f2e6e8e6daf0eee2 +e7e5d9f5f3e7f8f6eaeceadde6e3d2f9f6e5e5e1d5f9f5eceee9e3ece7e3f7f0e8e9e3d7 +eee7d5f1ebd5fcf6def9f3dbe6dfccf8f1dff6eee1ece6d8f2efe0e7e6d4e9e7daf0eee2 +faf7eededbd6fffbfae9e5e4e9e5e4f0ece9edeae3fbf8efe8e4d8fbf8e7e0ddcaf6f3e0 +e6e4d7fffff4dfddd1ebe9ddfaf8ece6e4d8f3f1e5edebdfebe9dde0ded2f1efe3f7f5e9 +edebdff0eee2edebdff7f5e9f2eee2ebe7dbf2eee2efebdfede9ddf8f4e8eeeadef0ece0 +efebdfede9ddf2eee2f6f2e6f9f5e9ede9dde2ded2f3f0e1f1eadaf5ecddf7e9e0f4e7e1 +f4ece9e8eae7e3f1f1899e9ff0fffff4feff0800100b000e0a001007081c000e15003423 +007a3f008843008a54004f303ee8e53fe6f643dbf2003f55001422e9f7fff8ffff000005 +fffcfffffcffebf1edfbfffa0404020100000100000100000100000c0b06010100040400 +0101000505000101000808000302000100000100000302000201000101000f0f07010100 +010100080800010100090901050500010100010100010100050500010100010100010100 +0707000101000101000101000a0a02090901010100090901010100010100010100010100 +010100010100010100010100010100010100010100010100010100010100010100010100 +010100010100010100010100010100010100010100010100010100010100010100010100 +010100010100010100010100010100010100010100010100010100010100010100010100 +0707000606000101001111090101000101001010080101000303000101000d0d05010100 +0c0c0401010012120a010100090901010100010100090901010100070700050500010100 +0b0b03010100010100111109010100010100080800010100010100050500010100050500 +0101000101000101000606000a0a02010100010100070700010100010100030300020200 +0b0b03010100010100111109010100010100080800010100090901010100080800010100 +0101000f0f070101000202000b0b03010100010100020200010100010100040400050500 +0808000101000f0f07050500010100010100010100060600010100010100010100010100 +0404000a0a02060600010100010100010100010100010100010100010100010100010100 +0002000a0c010002000102000a0b057f807ba7a7a7d9d9d9f8f8fafbfbfdffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8ff +f4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeeee2 +f5f3e7f6f4e8d6d4c8f1efe3f2f0e4eeece0e8e6dae5e3d7e6e4d8f6f4e8f7f5e9ebe9dd +eceadee6e4d8f6f4e7ffffede5e2cfdfdbcff6f2e9e4dfdbede8e5fff9f6f9f2ecfaf4e8 +eeebdaded8c8e1decdf8f2e4f2eee3e5e0daf9f5eceae7d8f6f5e3f6f3e4e4e2d5ede9de +f6f1ebe2ddd9f4efebf4efebefeae4ede6dce4ded0e6e1cef0ebd7f8f2daeee9d5f0edde +dddbcffefcf0e8e6daeceadef2f0e4eeece0efede1fffef2f4f2e6edebdff5f3e7e3e1d5 +eeece0f7f5e9dbd9cde9e5d9fcf8ece7e3d7eeeadef8f4e8dad6caece8dcf2eee2f5f1e5 +e2ded2f3efe3f1ede1d9d5c9f1ede1fffff3e7e4d3f1ead7f7ecd8fae8dcf7e6dff4ecea +e6eaebe3f1f2899ea1e7fffff2fffffaf7fffff8fffff7ff000017002535bdffff60f3c9 +009b6a00785c3ae3d023e7d300a08a00866c1c9782001209f2ffffeef7fefafaff170d18 +0b0708000600f3fff0feffff0100040100040c0a0d010000fffffd010000d8d7d3bfbeba +0706029796947c7b7905030483818209070a0503060907080100008988868887851f1e1c +807f7d9a99970100009392908685830e0d0b8887858b8a880100001b1a18010000010000 +908f8d060503070604010000010000adacaa81807e8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a +8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a +8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a +8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a807f7d +8c8b894d4c4a8c8b89030200060503010000070604040301010000010000010000030200 +12110f6a69673d3c3a908f8d7e7d7b9b9a980100000d0c0a01000088878592918f8c8b89 +8a89877f7e7c8d8c8a89888691908e8c8b89010000040301050402010000908f8d010000 +9695938988868b8a88010000a2a19f757472010000100f0d0100000100008d8c8a8c8b89 +8a89877f7e7c8d8c8a89888691908e8c8b890100000100009a9997807f7d1f1e1c888785 +8988860100000908060100009b9a9898979582817f1b1a180100008685838e8d8b8d8c8a +0706048a898792918f8887850f0e0c9a999781807e010000010000232220757472999896 +86858381807e9b9a988d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c8a8d8c888a8b85 +8f90888e8f878e8f8981827db2b2b0bababadcdcdcf9f9fbfcfcfeffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2 +e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeaeadeefede1 +f5f3e70f0d01eceadef3f1e5eae8dcf2f0e4fdfbef030100f0eee2eae8dcf0eee2e7e5d9 +fffff3e6e4d7dfdcc9eae7d4fffff3ebe7de100b08040000040000040000dfdbd2f2f0e3 +fffbeff1efe2f4f0e5e0ddd6f8f5f0e1ded7e3e0d1f4f1e0e9e3d3ece9daf6f0e4fef8ec +ddd6ccfff8eef1eae0faf4e8f5ede0ffffedede6d3f5efd7faf2dbe7e1cbf9f6e7f4f2e6 +dcdacefaf8ecf1efe3e1dfd3f6f4e8f2f0e4e3e1d5eeece0e8e6dae9e7dbf5f3e7fcfaee +dfddd1fefcf0e8e4d8f2eee2f8f4e8efebdfede9ddfffdf1eae6daf2eee2eae6dae9e5d9 +ebe7dbf9f5e9fcf8ecede9dde7e3d7f1eeddeeecd3f5edd6fde7daf9e4dff2ecece6eaed +e3f1f48a9da3ecffffe9fcffeff6fffffcfff9eeff00001bb4def474cdd543d0c730dbcb +37ebe23bf8e200995b00bc5f1ce9732cc45f001500fcfffdf8fafff9f6fffff4f8fffcf3 +f5ffefeffff0fafffffffefff7f6fefbfafffffefff3f3f5ffffffeaeaeacbcbcbababab +a4a4a6b5b5b7aeadb2b6b5bb0c0b139e9da3aaa9aeaaaaacb4b4b6a0a0a2a4a4a6afafb1 +9d9d9fb1b1b3a7a7a9a3a3a5a1a1a3a7a7a9b7b7b9b6b6b8a5a5a7a5a5a7b7b6bba9a8ad +020106aeadb2a5a4a9a8a7ac9d9ca1abaaafabaaafabaaafabaaafabaaafabaaafabaaaf +abaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaaf +abaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaaf +abaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafabaaafb0afb4b5b4b9 +56555aa2a1a6b1b0b5a5a4a99a999ec0bfc4b1b0b5adacb1acabb0b3b2b7adacb19d9ca1 +bcbbc03a393eabaaafaeadb2b5b4b9a9a8ada8a7acb2b1b6b7b6bb9f9ea3adacb1b4b3b8 +bdbcc1a3a2a7b2b1b6afaeb3bbbabfa2a1a6a1a0a5adacb1afaeb39c9ba0b6b5baa4a3a8 +a5a4a9b1b0b5adacb1b0afb4bbbabfaeadb299989daaa9aeb9b8bda3a2a7adacb1b4b3b8 +bdbcc1a3a2a7b2b1b6afaeb3bbbabfa2a1a6b1b0b59d9ca1afaeb3a4a3a8a09fa4b4b3b8 +aaa9aeaaa9aeb0afb4a6a5aab0afb49b9a9f9c9ba0bebdc2b5b4b9abaaaf0302079e9da2 +abaaafa7a6abb4b3b8a6a5aab5b4b9a4a3a8b0afb4a1a0a5a1a0a5b2b1b6b7b6bbaaa9ae +a6a5aab0afb4abaaafabaaafabaaafabaaafabaaafabaaafabaaafababadaaaba6a3a49e +adaea8b0b1acabaca7b3b3b1c0c0c0e3e3e3fafafafcfcfcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eada +ebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfe2e2d6f5f3e7e3e1d5 +040200e3e1d5f2f0e4e9e7dbf3f1e5e7e5d9030100eceadee6e4d8f2f0e4f6f4e8d6d4c8 +f4f2e5f6f4dfeae8d3dedbcce6e2d9130e0be5dfdfece6e6f5f0ed080500f5f3e7e6e4d8 +eceadef7f4ebe2dfd8e9e8e4f4f1ecf8f4e8f6f0e0fdf7e9e8e2d4f3eddfe1dbcdfffff1 +e8e2d4f2ecdee9e3d3e7e0d0f0e9d7e6dfccebe5cffcf6e0ebe6d3e1ddd1ebe9ddf7f5e9 +eeece0f1efe3f9f7ebe9e7dbe9e7dbf0eee2f1efe3f1efe3fbf9eddedcd0e3e1d5fffff4 +d9d7cbf7f3e7ebe7db040000e8e4d8f1ede1dfdbcffefaeee3dfd3f4f0e4fffff3e4e0d4 +d9d5c9f9f5e9faf6eaece8dcebead8eaeed3f3efd6fde7dcfbe3e1f2eceee5eaeee6eff6 +8e9ba3f2ffffe8f9fff4ffffe2e8f6fffbff0000199abed4337d880477745de8e34edee6 +00998d008f531bc45d2ad65047ca58001d00f7f9f4fffcfffffcfff4f6e9e9f3daf7ffef +f5fff4f7fbfefffefffffefff9f8fef4f3f8fffffff8f8faeaeaece5e5e7dfdfe1e1e0e5 +c7c6cbd4d3d9cccbd3000009dbdae2dddce2cfced3dfdee3e0dfe4dddce1dad9decfced3 +dfdee3dddce1dad9def7f6fbcccbd0c4c3c8dfdee3c8c7cceae9eee3e2e8cbcad0000005 +dddce2dad9dfd5d4dae0dfe5e2e1e7d8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7dd +d8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7dd +d8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7dd +d8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddcfced4626167 +c6c5cba8a7adbbbac0a4a3a9a2a1a7aeadb3a9a8aea7a6acacabb1b2b1b7a7a6aca4a3a9 +35343ae2e1e7d8d7ddcdccd2dcdbe1d7d6dcdfdee4d6d5dbd7d6dc010006000005000005 +0b0a10000005000005c4c3c9e0dfe5d7d6dcdbdae0d9d8dedddce2d7d6dcdbdae0dad9df +dedde3d7d6dcc9c8cecdccd2dfdee4dfdee4d0cfd5d1d0d6e1e0e6010006000005000005 +0b0a10000005000005c4c3c9e0dfe5dfdee4cfced4dad9dfdddce2e0dfe5dfdee4cfced4 +dddce2e2e1e7cccbd1d1d0d6e5e4eae1e0e6d3d2d8d3d2d8dad9df000005e3e2e8e9e8ee +dbdae0d1d0d6d1d0d6cfced4dddce2d6d5dbe3e2e8dfdee4cfced4d0cfd5e0dfe5e0dfe5 +cecdd3d8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7ddd8d7dce2e2e2d2d3cedadad8 +d4d4d2dcdcdad3d3d1e9e9e9fffffffbfbfbfdfdfdffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dc +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddffdfdf1e2dfd6fffef5030000 +131007f3f0e7dedbd2efece31b180f030000f5f2e9f7f4ebf6f3eadfdcd3fffff6e4e2d5 +f4f2ddf8f6e1f7f4e5f6f2e9040000fef8f8f1edeee3dfdeeae7e0030100ebe9ddf4f2e6 +eae7dee9e6dffffffbebe8e3e9e5dcebe7dce4e0d4f4f0e4ebe8d9efecddf8f5e6e2dfce +f9f6e5e4e1d0fffdede1dbcbfef8eaefe9dbf0eadcf2eee2fefcf0f3f0e7e8e5dcf4f1e8 +f4f1e8f2efe6d9d6cdf8f5ecf2efe6e5e2d9fdfaf1e1ded5edeae1edeae1f3f0e7f7f5e9 +e5e1d5f7f3e7040000f5f1e5f4f0e4f8f4e8e6e2d6fffbefe3dfd3e2ded2e7e3d7fdf9ed +ece8dcd9d5c9f1ede1f1f2e0e4f1d3edf1d8fde6defce2e5f1ecf0e3eaf0e7eef692999f +f9fffff4ffffeafdfbf2fffffffdff02031500051700131900180200170500111e00232f +001502002000001d00001e00000d00f5fffffffbfff4ede3eeffe3ebffe3f7fbedfff9fc +fffdffe7e6ecfffefffbfafffffffffffffff9f9f9fffffff1f1f1fefefee7e7e9fffeff +f2f1f7fcfbfff4f3fbf8f7fde6e5eaf8f8faf4f4f6e0e0e2eeeef0fbfbfdf1f1f3fbfbfd +ededefeeeef0e6e6e8f6f6f8fefeffededefededeff7f7f9eeedf2f9f8fdfdfcfffaf9fe +f0eff4f9f8fde6e5eaecebf0f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9 +f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9 +f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9 +f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9efeef3f6f5fa54535846454a +4e4d5251505543424762616647464b47464b4f4e533d3c414b4a4f55545959585d535257 +e2e1e6f4f3f8fffeffedecf1f8f7fce3e2e7f8f7fcf1f0f5f5f4f9fdfcfffffeffe4e3e8 +fefdffe8e7ecf5f4f9fbfafffffeffdcdbe0fefdfff9f8fde8e7ece4e3e8fffeffe3e2e7 +fffefff2f1f6f1f0f5f0eff4ecebf0f9f8fdfefdffebeaeff5f4f9fdfcfffffeffe4e3e8 +fefdffe8e7ecf5f4f9fbfafffbfafff1f0f5fbfaffeeedf2e0dfe4f4f3f8f8f7fce6e5ea +e8e7ecfffeffe9e8edfffefffaf9fee2e1e6fffeffe6e5eaefeef3edecf1e7e6ebf5f4f9 +fffeffefeef3fefdfff7f6fbf4f3f8f0eff4f3f2f7faf9fefbfafff5f4f9f1f0f5f3f2f7 +f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f5f4f9f8f8f8f1f1eff9f9f9eeeeec +fdfdfbeaeae8f7f7f5f1f1effdfdfdfffffffffffffffffffffffffefefffffeffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfe8e8dee4e1d8e4e1d8040100030000 +f6f3eafbf8efefece3030000030000f0ede4ece9e0030000f6f3eafbf8ef030100ecead5 +dfddc6f0eddee3dfd4040000eee8e8f4f0f1eae6e5fcf9f2030100fefceff4f2e5e0ded2 +100d04010000030000f8f5f0edeae3f9f6ef030000141205050300dddbccfefced030100 +fefcede3e1d4f5f3e7040100f6f3ec030000030000030000efece3030000030000f7f4eb +e7e4dbfffff6030000040100040100dad7cef7f4eb030000fcf9f0030000050300fefaef +ddd9cd060200050100eeeadef0ece0040000040000f7f3e7fffff3e7e3d7efebdffaf6ea +ece8dcf3efe3e6ebd7dff4d5e7f4dafde5e1fce1e6efedf2e3eaf0e9edf697989df9f9f9 +fbfffbf1fffae9fdf2fefffffffdfff8ffffe3f7f8ebfff4e9fff1f9ffffeef1fff5ffff +f0fff0f4ffe8f8ffeff4fffff9fffffdeaecfffef1deffd6e9ffe8fffffffff3fffffcff +fffefff7f7f9fbfbfdfdfdfdfffffdfffffdededebfffffdfffffdf4f4f4f9f9fbfcfbff +fffefffffefff8f7fcfffffffafafafffffffffffffffffffefefefcfcfcf7f7f7ffffff +fffffffffffffbfbfbfffffffffffffbfbfbf8f8f8fffffffbfbfdfffffffafafcffffff +fafafcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefefffcfcfeededefffffff +f4f4f6ffffffe9e9ebfffffffffffffffffff8f8faffffffffffffe6e6e8ffffffffffff +fffffff4f4f6f6f6f8fffffffffffffffffffffffffdfdfff7f7f9f3f3f5fefeffffffff +fafafcffffffe8e8eaf9f9fbfffffffcfcfefafafcfffffffffffff5f5f7ffffffeaeaec +fffffffffffffffffffffffffffffff4f4f6fbfbfdfdfdfff7f7f9f3f3f5fefeffffffff +fafafcffffffe8e8eaf7f7f9fcfcfefefefffffffffffffffffffffafafcffffffffffff +f7f7f9fffffff7f7f9f5f5f7fffffffffffffffffffffffffffffffffffffffffff1f1f3 +f7f7f9f5f5f7fffffffffffffefefff8f8fafefefffefefffafafcffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffbfbfdfdfdfdfefefef7f7f7fffffd +fefefcfffffdfafaf8fefefefffffffffffffffffffffffffefefffffeffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfeeeee4f1eee5f0ede4090600fffcf3030000 +dfdcd3050200efece3070400f1eee5e7e4db030000f4f1e8dcd9d0141205f2f0dbf0eed7 +fffeeff2eee30e0906dfd9d9ebe5e5f0ebe8ebe8e1090700e1dfd0dedccd201e0fdedccf +f2efe6f7f4ef030000e7e5e6080703f0efeae3e3d9e3e3d717180ae3e4d6010200e6e6da +e1e3d8eff0ea000000ebebeb0e0d12e7e7e9dedbd616130aeeebe2f2efe6060300eeebe2 +030000e8e5dce4e1d8fffff6060300ece9e0030000030000f6f3eaf3f1e5040000f9f5e9 +040000e6e2d6e8e4d80d0900f0ece0faf6ea0a0600cecabefffbefe3dfd3ede9ddf1ede1 +f7f3e7e4ebd9dbf6d7e3f5dbfbe6e3fce1e8efecf3e3eaf2ececf499979afffdfafbfdf0 +f1fff15c745c797b6e6b63606660647b7b7d68716c828481f7e3eefffafff5fffbecfff6 +fefffffff7fffffafff9ecfefff4fbfffbf7f7fff4e5f9f0fafafffff9fffffdfff9f9f9 +fffffdfffffdfffffbf5f6f1fbfcf6fffffafffffaeff0eafffffbfffffdfcfcfcffffff +f7f6fbfffffff8f8f6fffffbfcfdf8f4f5f0f3f4effffffbfffffbfefffafffffbfffffb +f0f1ecfffffbfffffbe8e9e4fcfdf8fffffbfcfcfaffffffe7e7e7fffffffffffffefefe +fffffff7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffafafafffffffffffffffffffafafaf9f9f9 +f4f4f4fffffffffffff9f9f9fbfbfbfcfcfcfffffffffffffdfdfdfffffffcfcfcffffff +fffffff7f7f7fffffff3f3f3f8f8f8fffffffffffff7f7f7fffffffdfdfdfffffffefefe +e6e6e6fffffffffffffefefefffffff9f9f9fffffffafafafcfcfcfbfbfbffffffffffff +f0f0f0f6f6f6fffffffffffff7f7f7fffffffffffff7f7f7fffffffdfdfdfffffffefefe +e6e6e6fffffffefefefffffffffffff3f3f3f4f4f4fcfcfcfffffff8f8f8fffffff4f4f4 +f8f8f8fffffffffffffdfdfdffffffffffffffffffe8e8e8ffffffffffffffffffffffff +fffffff4f4f4fafafafffffffffffffffffffdfdfdfffffffdfdfdf0f0f0ffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffafafaf9f9f9fffffff5f5f5 +fffffdfbfbf9fffffffffffffffffffffffffffffffefefffffeffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfe5e5dbfbf8efeae7de030000e6e3da040100fbf8ef +030000eeebe2030000f6f3eae8e5dc0a0700f3f0e7e8e5dc040200ebe8d5f7f4e1e8e5d6 +ebe7dc090400f5f0ecede8e5f0ebe7eae7de040200faf8e9eeecdd030100fcfaede8e6da +f1eee7040000eceaeb060503edeee8f1f1e9f1f3e8dadacef4f6e9070700e6e8ddf5f6ee +e4e5df020200f0f0f2000004f2f2f2f5f4ef030100f8f5ece5e3d7090600ebe9dd040100 +060400060300030100030000f8f6ea030000ebe9ddece9e0ebe9dd0d0900ece8dc050100 +f6f2e6f5f1e5f1ede1040000f0ece0e7e3d7fffcf0e7e3d7f1ede1f4f0e4e3dfd3f6f2e6 +e6ead9dcf4dae5f4dffae7e3fbe2e6efedf0e5eaeeececf499979cfff8f6fffff3697d64 +eaffecf8fffffefffffffdfffffdfff8ffffeaeefa8e7e8b786d755265616b817e6c6f78 +fff8fffff7fffff9fffff9fffffcfbf6f8f5f8fffffbfcfff9f9fffcfcfffffffdfffffd +f7f8f3fffffbfbfcf7fffffafbfcf6fcfdf7fffffaf5f6f1fffffdfcfcfcfdfdfdffffff +f6f6f6fefefcfffffbfbfcf7fffffbfffffbfdfef9f7f8f3fffffbfafbf6fffffbfffffb +fbfcf7fffffbfffffbfefffafffffbfffffdfafaf8fffffdfffffdfcfcfaf6f6f4fffffd +fffffdfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefc +fefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefc +fefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefcfefefc +fefefcfefefcfefefcfefefcfefefcfefffd8b8d8c7e7f837e7e868786948281938c8aa0 +7f7d9582809683819686859592919f79798378797e8f90947f80828f8f8fededebfffffd +fffffdf1f1effffffdfffffdfffffdfffffdf2f2f0fffffdfffffdfefefcfffffdf8f8f6 +fffffdfffffdfffffdfffffdf9f9f7fffffdfefefcfffffdfffffdfffffdfefefcfdfdfb +fffffdfffffdfcfcfafbfbf9fffffdfffffdf2f2f0fffffdfffffdfefefcfffffdf8f8f6 +fffffdfffffdf7f7f5fdfdfbfffffdfffffdfbfbf9fffffdfefefcfffffdf9f9f7fffffd +fffffdfffffdfafaf8fbfbf9fcfcfafbfbf9fffffdf8f8f6f1f1effffffdf9f9f7f9f9f7 +fffffdf7f7f5fffffdfffffdfcfcfafcfcfafffffdfffffdfffffdfefefcfefefcfefefc +fefefcfefefcfefefcfefefcfefefefafafafffffff7f7f7fffffffffffff6f6f6fffffd +fffffdfffffffffffffffffffffffffefefffefeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddff9f9efd6d3cafcf9f0030000dfdcd3f5f2e9030000f7f4eb +e8e5dc070400f2efe6f1eee5030000f2efe6f0ede40b0900eae7d8e7e4d5fffbeff0ece0 +040000e8e4d9fffff6e8e4d9e4e0d50e0a00ede9ddf4f0e4070300e6e2d6f1ede1eae8dc +040100eeebe6080500eeeee6f3f0e7f2f2e8dcd9d0f5f5eb060300f2f2e8e0e0d6f5f5ed +010100eae9e4020100ecece4f4f1e8060400dcdacef7f5e8030100f9f7ea030100f2f0e3 +e6e4d8f9f7eaeceadef3f1e4030100f1efe2eceadeefede0050100e7e3d70f0b00efebdf +dbd7cbfdf9edf7f3e7040000e7e3d7fffcf0e7e3d7f1ede1f4f0e4e3dfd3f6f2e6e7e9db +e3f0dceaf1e1f7e8e1f8e5e1f2eee5e8eae7e9edf69797a1fffcfdfcf9f07a8678edffff +eaffffe6feffbccde9a6bad3a3c0deceebffdff3fff0ffffe4fcffe2f7fcaeb7bc636468 +fffffffefaf9fffbf8fbf7f4fffffffcfffff4f3fffefdfffffefff7f7f7fffffffdfdfb +fffffdfefefcfffffdf9f9f7fffffdf7f7f5fffffdfafafaf6f6f6fffffff3f3f3ffffff +f2f2f2fffffdfffffdfffffdf3f3f1fffffdfbfbf9fffffdf6f6f4fffffdeeeeecf7f7f5 +fffffdfcfcfafffffdfefefcfffffffffffff7f7f7fffffffcfcfcfdfdfdfffffffefefe +fdfdfdfffffff6f6f6fffffffffffffffffffffffffdfdfdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffefffdfbfffb7c8584bac0cebfc3e0cacbfbbcbbf7ccc9ffbab6ff +bdb9ffc2c0ffb6b6ecc5c6f2c7cae9b5bad0cbd1e17a7e87000004fefefefffffffefefe +f4f4f4fffffff4f4f4fffffffffffffefefefcfcfcf7f7f7fffffffffffffffffffbfbfb +fafafafffffffffffff5f5f5fefefef4f4f4fffffffcfcfcf9f9f9fffffffffffff9f9f9 +fffffffafafafffffffffffffffffffffffff4f4f4fffffffdfdfdfffffff7f7f7ffffff +fffffffffffffafafafdfdfdfffffffffffffffffff9f9f9ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc7 +0837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfecece2fffff6d4d1c80c0900fefbf2efece3040100e7e4dbedeae1 +080500ebe8dfe3e0d7fdfaf1040100030000efede1f8f4e9e9e5d9d9d5c9ebe7db161206 +e0dcd0efebdfe9e5d9100c00e4e0d4e1ddd1f3efe3050100e8e4d8f7f3e7f1ede1030000 +e9e6dd0a0700f2efe6e5e2d9e5e2d919160de5e2d9030000e3e0d7fbf8ef080500030000 +f4f1e80e0b02e8e6daf2f0e4030100fffdf0e8e6d9141205e5e3d6040200eeecdffbf9ec +e1dfd2040200eae8db030100f7f5e8e5e3d6f2f0e30a0600e9e5d9040000f1ede1f2eee2 +040000dedacef5f1e50a0600cecabefffbefe3dfd3ede9ddf1ede1f7f3e7e8e9dbe7eede +edefe1f6e9e1f7e6def4eee2e9eae4e9edf89498a4fffdfff7f4ef717b72eeffffd2f3ff +89addf84a0c5809ec07198c182acd48cb0d4d1f3ffeafffff0ffff99a7aa5f6865f4f9f3 +fefffafffffafffffbf2f2f2fffffffefffff6f7fcf5f5f7fefefefffffffffffff7f7f7 +ffffffe8e8e8fffffffffffffffffff4f4f4f7f7f7ffffffefefefffffffffffffffffff +eeeeeefdfdfdf3f3f3fffffffffffffffffffafafafffffff0f0f0fffffffffffff7f7f7 +fdfdfdfffffff6f6f6fffffffffffffafafaf4f4f4ffffffffffffedededfdfdfdeeeeee +fffffffcfcfcfffffffffffffffffffcfcfcffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffefffff6fcf88e9899cdd2e5070b2e04033c050448070252100d5e0b0656 +1d1c620a094500002b0c0e34141a34090e247e8190000005fffffffffffffcfcfcffffff +f0f0f0fffffffffffffffffffcfcfcfffffff5f5f5fffffffefefef2f2f2fffffff5f5f5 +fffffffdfdfdfdfdfdffffffffffffedededfffffffbfbfbffffffe8e8e8ffffffececec +fffffff5f5f5ffffffffffffebebebffffffe8e8e8fffffffffffffffffffafafaf5f5f5 +fffffffffffffffffff8f8f8f9f9f9ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db +1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfd8d8cefcf9f0f8f5ec030000eae7def3f0e7f0ede4fefbf2eeebe2030000 +f9f6ede5e2d9f0ede4060300edeae1f2f0e4e9e5dafffcf0fefaeee8e4d8040000110d01 +040000090500e8e4d8efebdffffcf0ebe7dbe3dfd3040000090500040000f8f5ecedeae1 +f9f6ed030000141108050200dddad1fefbf2f6f3ea090600030000fcf9f0030000e7e4db +030000efede1e9e7db030100eceadde6e4d7030100fffff2f1efe20301000301000b0900 +e5e3d6fcfaed030100ebe9dcf5f3e6e1dfd2040000e7e3d7ebe7db0f0b00dbd7cbfffff3 +070300040000f7f3e7fffff3e7e3d7efebdffaf6eaece8dcf3efe3e8e9dbe7eedcedefe1 +f6e9e1f7e6def4eee2e8ebe4e7eef89498a4fffbfffefdf9747f77eeffff98b9e2678cc0 +c5e3ffe6ffffdfffffacd7ffa4caf184a5c4d7f1ffdef4ff97a6ab6c7675fbfffdf1f4ed +fefff9fefffafffffde6e6e8fffefffffefffefefffffffffffffffdfdfdfffffff8f8f8 +fffffffffffffffffff7f7f7fffffffffffffffffffffffffffffff0f0f0e2e2e2ffffff +fffffffffffffefefef7f7f7fffffffefefef5f5f5fffffffffffffdfdfdfffffff3f3f3 +fffffffffffff4f4f4fffffff7f7f7ffffffffffffffffffffffffffffffffffffffffff +fbfbfbeeeeeefffffffffffff8f8f8ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffefffffbffff767e81b4b7c60b0f28121236070932110f3e0f103e0c0b35e1e3ff +0a0b2af9fdff04061df6fbff000013989bac030409fafafaf9f9f9f8f8f8f9f9f9ffffff +fffffff5f5f5f2f2f2fffffff6f6f6f8f8f8fcfcfcfffffffffffffefefeffffffeaeaea +ffffffffffffefefeffefefefafafafffffffffffff9f9f9fffffff9f9f9ffffffffffff +fffffffafafafbfbfbfffffffffffffffffff7f7f7fafafafafafafefefefffffffbfbfb +f3f3f3f9f9f9fffffffffffffefefef9f9f9ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff3 +1e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddff9f9ede7e4dbe2dfd6fbf8eff1eee5f1eee5e5e2d9e3e0d7eeebe2e4e1d8fbf8ef +e9e6dde0ddd4120f06f7f4ebedebdfece8dcdcd8cce3dfd3fbf7ebede9ddf1ede1f8f4e8 +e6e2d6fbf7ebeeeadededacef7f3e7ece8dcfaf6eae8e4d8efebdfe8e6daeae7dee3e0d7 +f3f0e7eae7deeeebe2f7f4ebe1ded5e8e5dcedeae1efece3e5e2d9efece3e9e6ddf6f3ea +f8f6eae4e2d5fffff2f7f5e8eceaddf5f3e6ebe9dcedebdee8e6d9e8e6d9e3e1d4f1efe2 +eae8dbf4f2e5f6f4e7eeecdff7f5e8fffbeffcf8ece0dcd0eeeadefffff3dad6caf4f0e4 +eae6dae3dfd3e2ded2e7e3d7fdf9edece8dcd9d5c9f1ede1f1f2e4e7eedcedf0dff6e9e0 +f5e6dff4eee2e8ebe4e7edf99298a6fdfbfffffffb6a756de3fcff88abd5aacfffe2ffff +c8e8ff9ac3f183adddd1f6ff91b3d6cbe6ffebffffa8b9c1606b6dfbfffffbfffaeceee9 +fffffbfffffd0505050a090e000004000002f6f6f6fffffff1f1f1f6f6f6ffffffffffff +efefeffafafaffffffffffffedededffffffffffffeeeeeefffffffffffff4f4f4fdfdfd +f5f5f5fafafafafafa181818000000fffffff8f8f8ffffff000000000000ffffffeaeaea +fffffffffffff7f7f7ffffffeeeeeefefefee7e7e7fffffff4f4f4f3f3f3f0f0f0ffffff +fffffffffffff9f9f9f4f4f4ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffffcffff81868cc8cad67e81908485978d909f787a87777b8484878c808588888c8d +8b90937f828b7b7e8da1a2b76c6d7f000005fffffffbfbfb0d0d0dfffffffffffff5f5f5 +fffffffffffffffffffcfcfcffffffffffffeaeaeafffffffffffffbfbfbf9f9f9070707 +fffffffffffff6f6f6fffffffffffffffffffdfdfdf7f7f7fffffff3f3f3fefefeeeeeee +ffffffffffffffffffe6e6e6fffffffffffffffffffffffffffffff5f5f5f9f9f9fbfbfb +fffffffdfdfdfafafaf3f3f3ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bc +e2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +e7e7dbeae8dcf1efe3eeece0ebe9ddebe9ddfffef2f2f0e4f5f3e7f0eee2e8e6da030100 +131105dddbcfe5e3d7eceadefaf6eaf7f3e7f5f1e5e9e5d9f8f4e8dcd8ccf5f1e5f5f1e5 +e2ded2fffff3ece8dcf4f0e4ede9ddeeeadeebe7dbf3efe3f7f5e9f3f1e5faf8ece5e3d7 +f0eee2dedcd0fffff4e5e3d7fcfaeedddbcffffdf1dddbcfedebdffffff4d8d6cae8e6da +f2f0e3e7e5d8f2f0e3e3e1d4e9e7daeae8dbeeecdff3f1e4e8e6d9fdfbeef2f0e3f0eee1 +e4e2d5dcdacdefede0ebe9dce5e1d5ddd9cdf5f1e5f7f3e7e0dcd0f5f1e5e4e0d4efebdf +f4f0e4fffff3e4e0d4d9d5c9f9f5e9faf6eaece8dce9eadce7eedcedf0dff6e9e0f5e6df +f4eee2e8ebe4e6eef99298a6fffdfffffffd6f7c75e4ffff7398c4d7feffd0f0ff90b0d7 +83abde83aee3dcffffbddeff7895b3e6ffff99abb7586669f1faf9f4f9f5fefffbf3f4ef +010000fffefffbf9fcfffefffefefefffffffffffffffffffffffffefefef6f6f6ffffff +fffffff8f8f8ffffffffffffffffffeaeaeafffffff6f6f6fffffffffffffefefeffffff +fffffffafafa000000040404fbfbfbfbfbfbffffff0b0b0b090909f1f1f1fffffff9f9f9 +f1f1f1f6f6f6fffffffffffffffffffffffff7f7f7fffffffffffffcfcfcfdfdfdffffff +fcfcfcfffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefeff72757edfdfe7e9edf0fbfdfafcfff6f5fae4fcffe8feffe3fbffe2feffe8ebf3de +fefffbfcfffff4f3ff81809209080effffffffffff000000fdfdfdf5f5f5ffffffffffff +f9f9f9fdfdfdf5f5f5fffffffffffff1f1f1ffffffebebebfffffffafafa000000fefefe +fffffffdfdfdfdfdfdf4f4f4fafafafefefefffffff8f8f8fcfcfcffffffffffffffffff +ecececfffffff4f4f4fffffffffffffffffffffffff5f5f5fbfbfbfffffffffffff8f8f8 +fcfcfcfffffffbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8ff +f4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddff1f1e5 +ebe9ddedebdff0eee2f1efe3eceadee4e2d6e9e7dbefede1dedcd0fffdf1f0eee2e5e3d7 +fefcf0fbf9ededebdfe2ded2f0ece0e6e2d6f2eee2f9f5e9f7f3e7eeeadeece8dcf2eee2 +eeeadee8e4d8e4e0d4f9f5e9e9e5d9f0ece0f0ece0e2e0d4f3f1e5e6e4d8ebe9ddf3f1e5 +fbf9eddad8ccfcfaeef9f7ebe4e2d6efede1fcfaeee5e3d7dddbcffffdf1eae8dcf3f1e4 +d5d3c6fefceffefcefeceaddf7f5e8e6e4d7ebe9dcf2f0e3eeecdfe0ded1f6f4e7f6f4e7 +eeecdffefcefe7e5d8f2eee2fffff3efebdfdedaceeeeadef5f1e5f1ede1fdf9edeae6da +e9e5d9ebe7dbf9f5e9fcf8ecede9dde7e3d7f0eedfe9eedaeeefddf7e9e0f7e6dff2eee2 +e8eae5e6eef99198a8fefdfffffffd6f7e79eaffff6489b5dbffffe4ffffdfffff79a1d5 +6d95d0dfffffe2ffff84a1c3eaffffa4b5c55f6c74f5fdfffbfffffafcf9000100fffffd +f8f7f5fffefffcfafbfafafaffffffe8e8e8000000141414000000ffffffffffff050505 +000000000000fcfcfc000000121212fefefeffffff0000000000000b0b0b000000ffffff +ffffff000000ffffff000000ffffff000000ffffff000000f8f8f8f4f4f4000000050505 +080808fffffffefefe0000000b0b0b000000060606e7e7e7fffffff6f6f6fffffff7f7f7 +fffffffffffffafafaffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffdff +797985c6c5cbfefffdfffff3eef4d8ffffdc5f69356f783f000a00fbffd2feffe3fefff0 +fefffffcfaff8a8798000005e5e5e5fdfdfd0f0f0f0000000b0b0bf3f3f3ffffff080808 +030303080808f2f2f2f1f1f1ffffff0000000b0b0b000000ffffff0b0b0b000000000000 +ffffff000000141414020202fcfcfc030303000000fffffffafafaf0f0f00303030a0a0a +000000efefeff9f9f9f3f3f3050505000000131313000000dadadafffffffffffffdfdfd +fffffffcfcfcf7f7f7ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2 +e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddff6f6eae2e0d4 +e8e6dafaf8ece5e3d7f8f6eaf2f0e4f2f0e4e8e6dafffdf1e7e5d9f0eee2f4f2e6d0cec2 +f3f1e5e9e7dbf6f2e6f6f2e6ece8dcefebdfe7e3d7f7f3e7ebe7dbf0ece0f1ede1e8e4d8 +f3efe3fffef2dad6cafdf9ede9e5d9f0ece0e9e7dbf6f4e8f5f3e7e4e2d6eceadef5f3e7 +e1dfd3f3f1e5e3e1d5fdfbefe9e7dbefede1f1efe3f6f4e8e0ded2faf8ecefede0fffef1 +e1dfd2dbd9cce9e7daf4f2e5f0eee1eae8dbe6e4d7f8f6e9efede0fbf9ecd6d4c7faf8eb +e3e1d4f1efe2e9e5d9efebdfefebdfece8dcfefaeee9e5d9e5e1d5e2ded2f5f1e5e2ded2 +f3efe3f1ede1d9d5c9f1ede1fffff3e6e4d5e9eedaeeefddf7e9e0f7e6def2eee2e6ebe5 +e5effb9198a8fffefff4f6f55c6b66ebffff7ea3cfccf1ffe6ffffe1feff8fb4e97098d3 +dfffffd7f9ff8eaacfd0e8ff9cafc058666ff7ffffeff5f5fefffd0c0c0afffefcf4f3f1 +fffffdf9f7f8f6f6f6fffffffffffffdfdfdfffffff6f6f6040404f9f9f9000000ffffff +fefefe030303fffffff7f7f7000000fbfbfb000000fffffffffffff5f5f50a0a0af8f8f8 +000000ffffff111111f1f1f1000000fcfcfc000000fffffffffffffefefeffffffffffff +000000f7f7f7040404fffffff8f8f8f6f6f6151515e9e9e9fffffffffffff9f9f9f8f8f8 +f0f0f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffefff0eef99795a0 +c6c4c9fdfef8f4f5e3ffffe3fcffd20f1900e7f0af788341030a00fcffd9ffffede2e3de +fffdff8482900f0e13fffffff8f8f8000000f8f8f8fbfbfbffffff000000f9f9f9ffffff +f3f3f3050505ffffff000000f7f7f7fffffffafafaffffff0f0f0fefefefffffffffffff +040404f1f1f1fdfdfd000000ffffffffffff000000f2f2f2fffffffcfcfcf6f6f6ffffff +030303ffffff000000f0f0f0fffffffafafa0e0e0efffffffffffff3f3f3f6f6f6ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eada +ebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeaeadef2f0e4efede1 +f8f6eae3e1d5f2f0e4e7e5d9f1efe3f2f0e4eae8dceae8dcf4f2e6eceadefefcf0ebe9dd +f0eee2f1ede1e3dfd3f8f4e8eae6daefebdfeeeadeeeeadeede9ddf0ece0faf6eadfdbcf +f6f2e6f5f1e5e2ded2ece8dcf0ece0f1efe3e7e5d9e9e7dbf0eee2faf8ecdedcd0fffdf1 +e9e7dbf7f5e9eae8dcebe9ddf1efe3eeece0f6f4e8eae8dcedebdfe4e2d5f7f5e8edebde +f3f1e4faf8ebedebdee4e2d5f6f4e7f8f6e9e4e2d5efede0ebe9dcf9f7eaeae8dbf0eee1 +eae8dbf3efe3e3dfd3f6f2e6f2eee2e7e3d7f1ede1f8f4e8f0ece0efebdfede9ddf2eee2 +f6f2e6f9f5e9ede9dde2ded2f2f0e1e9eedaf0efddf9e8def7e6def2eee2e6ebe5e5effb +9099aafbfcfffeffff6d7c77edffff7b9ec895b9ede7ffffe7ffff7d9ed483a7e1ddffff +e0ffff89a5cae4fcff99acbd65737ef8fffff9fffffcffff000100fffffdfffffdf8f7f5 +fffffdffffffe9e9e9ffffff000000000000000000060606ffffff050505fcfcfcffffff +000000fefefefbfbfb080808fdfdfd020202f9f9f9ffffffffffff000000ffffff000000 +fbfbfbf1f1f10c0c0cf7f7f7ffffff000000fffffff7f7f7020202000000000000070707 +ffffff000000fafafaffffffffffff000000fffffffbfbfbf5f5f5fffffffffffff1f1f1 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffdff86838cc9c7cc +f8f7f2fffff1ffffe4696f43e9f0ba878f53878f53010800767b53feffeafffffafffdff +87848f000004ffffffffffff000000ffffffffffffe9e9e90e0e0e070707000000080808 +020202eeeeee070707101010f8f8f8fffffff6f6f6000000fffffffffffff2f2f2060606 +ffffffffffff010101fbfbfbffffff020202ffffffededed0b0b0b070707000000000000 +fcfcfc000000fffffffffffffefefe000000fffffff7f7f7fffffffffffff4f4f4fafafa +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dc +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeceddfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecddeaeddaf0efddf9e8def7e6def2eee3e6ebe7e3effd9099aa +fcfdfff4f6f56d7a73eeffffb5d5fe7d9dcec1d9fbeaffff88a6da7495cbe3ffffdffcff +7892b5e0f5ffb2c3d554626bf8fffffbfffffafefd000100fffffdfaf9f7fffcfbfffefc +fefefefcfcfc000000fffffffffffffdfdfd050505ffffff0b0b0bf8f8f8f8f8f8040404 +fefefeffffff000000ffffff080808f6f6f6fffffff4f4f4000000ffffff000000ffffff +ffffff000000fffffffdfdfd020202ffffff000000fffffffcfcfcfcfcfc0c0c0cfefefe +000000fffffffffffff9f9f9000000fffffffbfbfbf5f5f5fffffffffffff1f1f1ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffeff838087c0bec1fffffd +fffff8f7f8e8ffffe8010500c1c69deff5c9010600feffe2ffffeffffffafffeff86838a +000002ffffffffffff000000f6f6f6ffffffffffff000000fafafafffffffffffffbfbfb +fcfcfcfffffff3f3f3010101111111e7e7e7131313f9f9f9f8f8f8ffffff000000ffffff +ffffff050505fffffff6f6f6050505ffffff000000fffffffdfdfdffffff000000ffffff +040404efefefffffffffffff060606f9f9f9fffffffffffff6f6f6ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeceddfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecddeaeddaf0efddf9e8def7e6def2eee3e6ebe7e3effd9099aafffeff +fffffd6c776fecffffd4f0ff839fce8497b7c9dcfccee9ffe4ffffe7ffffb6cff7a8bfdf +ecffff899aaa66737ceaf4f6f0f6f6fcfffff7f9f611100efffffdfaf6f5fffffdfffeff +f1f1f1010101ffffffe0e0e0fdfdfd000000f7f7f7000000ffffffffffff000000fafafa +ffffff000000ffffff000000fffffffafafaffffff000000f0f0f0101010f5f5f5efefef +fffffff5f5f5f6f6f6040404f3f3f3030303fefefeffffffffffff000000fdfdfd000000 +f8f8f8efefefffffff151515e9e9e9fffffffffffff9f9f9f8f8f8f0f0f0ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffeff878588cdcbcefffefffffeff +fffffbf0f0e6fffff1080a00050700feffe8ffffedf9f9edf3f2edfdfbfe939196010103 +fffffffefefe000000fffffff5f5f5fafafa000000ffffffffffffffffff050505f9f9f9 +f9f9f9fffffffefefe000000ffffff000000fcfcfcfffffff2f2f2000000fbfbfbfdfdfd +020202ffffffffffff050505f5f5f5000000f9f9f9fafafafefefe000000ffffff000000 +fffffff7f7f7ffffff000000fcfcfcfbfbfbfffffffffffff5f5f5fbfbfbffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfecedddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeecdde9eedaeeefddf7e9e0f5e6dff1efe3e5ebe7e5effb9198aafcfafffdfcf8 +71796ef4ffffe1f8ffeaffff9caac479859f879ac2eaffff9db3da9aaecfd1e5fedff0ff +9fadba69767cf8fffffbffffedf1f0fcfefbf3f2f0010000030000010000010000ffffff +f6f6f6050505131313030303090909ffffff121212f2f2f2fcfcfc060606efefefffffff +000000ffffff070707000000000000000000fcfcfcffffff000000ffffffffffffffffff +f6f6f6ffffff000000fffffffcfcfc070707000000000000000000ffffff000000151515 +070707000000e7e7e7fffffff6f6f6fffffff7f7f7fffffffffffffafafaffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffdfaf9f5878684c3c1c4fffefff8f5fefffdff +f0eef3fffefffffffbedede5fffff5fffff6fffff8fffffbfffeff757376000000ffffff +fefefeeeeeee000000030303f3f3f3ffffff080808000000000000ffffffffffff090909 +000000000000fbfbfbf9f9f9f4f4f4000000000000ffffff000000ffffffffffff000000 +fefefefdfdfd000000ffffffffffff020202000000000000000000ffffffe7e7e7111111 +000000040404010101fffffffffffff1f1f1fffffffffffffffffff6f6f6ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfecedddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecdde9eedaeeefddf7e9e0f5e6dff1efe3e5ebe7e5effb9198a8f3f1f4fffef8e7ebdd +828e8ce5f8ffd5e5fff8feffe1e8fbdcebff91a4c59cadcbe6f6fff2fffff4ffffa2afb7 +5a6569f9ffffecf2f0fcfffdf6f8f5fffffdfffffdf6f2f3fffefffffffffcfcfcffffff +f9f9f9fafafafffffff0f0f0f8f8f8edededfffffffffffffcfcfcffffffffffffffffff +fdfdfd000000fffffffffffffffffffffffffdfdfdeeeeeefffffff0f0f0ffffffffffff +fffffffffffff5f5f5fffffff4f4f4fdfdfdfffffff7f7f7ffffff000000f4f4f4fcfcfc +fafafafffffffcfcfcfdfdfdfffffffcfcfcfffffffffffffefefeffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffdfbfcf48f908a8b898a7c7b81827f8a8d8b98918d9b +8b89948583889090908786827778727877738f8f8d7371748c8c8e0e0e0ef1f1f1fdfdfd +fffffffffffffffffffffffff9f9f9fffffffffffffffffff5f5f5fffffff0f0f0fdfdfd +fcfcfcfffffffefefefffffff1f1f1fafafafafafafefefeffffffffffffffffffffffff +ffffffffffffebebebffffffeeeeeefffffff9f9f9fbfbfbffffffffffffe5e5e5ffffff +f6f6f6000000eeeeeefffffffffffffcfcfcf6f6f6fffffffdfdfdffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddfecedddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdd +e9eedaeeefdff7e9e0f5e6dff1efe3e5ebe7e5effb9298a6fffefffffef6fffff1ecf5f0 +72809a7580a075778670707c60687ff4fffff4ffffe0ebfdeffbffe5f2faa8b3b5606a6b +f7fffdfbfffdfcfffdfefffdf3f3f3efefeffffefffffdfff9f9f9fbfbfbffffffffffff +f7f7f7f0f0f0fffffffffffffffffff9f9f9f5f5f5fbfbfbfffffff4f4f4fffffffdfdfd +060606fdfdfdfefefef5f5f5fbfbfbfdfdfdfffffffcfcfcfffffff4f4f4fffffffcfcfc +fffffffafafafffffff7f7f7fdfdfdfbfbfbfefefeffffff050505fcfcfcfcfcfcffffff +f3f3f3f0f0f0fffffffffffffffffff9f9f9f4f4f4ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff60002000001000f101200000702020c000009000007 +000004080a0900000000010009090700010009090b000002020202fdfdfdffffffffffff +f8f8f8efefeffffffff6f6f6fefefeeaeaeafffffffffffff5f5f5ffffffffffffffffff +fbfbfbf6f6f6fdfdfdfffffffffffffdfdfdfffffffffffffefefeffffffefefefffffff +f9f9f9fbfbfbffffffffffffe4e4e4fffffff9f9f9fffffffdfdfd0a0a0a0000000c0c0c +fffffffffffff4f4f4fafafafffffffffffffdfdfdfefefeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc7 +0837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfecedddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdde9eddc +eeefdff7e9e0f5e6dff1efe3e5ece5e6eefb9298a6fffcfcfef6ebf9f8e6fcfffae9f4ff +f7fefff1eef9fffdfffbfeff6f7688585f6f7179847780876d7779788281f9fffffbfffd +f4f9f5fefffdf8faf7fffffffffffffffefff9f7faf7f7f7fffffff5f5f5fdfdfdffffff +fffffffffffff1f1f1f8f8f8fffffff1f1f1fefefeffffffefefefffffffffffffeeeeee +ffffffedededfffffffafafaf9f9f9ffffffffffffecececf6f6f6fdfdfdfffffffdfdfd +fffffffafafafffffff4f4f4ffffffffffffeaeaeafffffffffffff2f2f2fcfcfcffffff +fffffffbfbfbeeeeeefffffffffffff8f8f8ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbf4f7ecfefff4fefffafafcf9fefffffeffffeff0f5fdfefffeffff +f7f9f4f6f9f2fefffafbfdf8fefffffefffffefffffbfbfdf6f6f6fffffff6f6f6fbfbfb +fffffff5f5f5fffffffffffffbfbfbfffffff0f0f0fffffffffffffffffff9f9f9ffffff +fffffff0f0f0fffffffffffffffffff8f8f8fffffffdfdfdf2f2f2ffffffffffffffffff +fffffff6f6f6fffffffffffffffffffbfbfbfafafaf9f9f9fffffff5f5f5fafafafdfdfd +edededfffffffffffffbfbfbfafafaf8f8f8ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db +1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfecedddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdde9eddcedf0df +f6e9e1f4e7e1f1efe3e5ece5e6eefb9497a6fffcfdf4eae0ffffecfefff5f5fcfff9fdff +fffcfff6edf0fcfcfffbfffffbfffffbfffff9fffff4fdfcf7fffbf9fffbfbfffbfcfffb +fdfffcf3f5f2fefefeffffffe1e0e5fffffffffffff4f4f4fffffffffffffffffff6f6f6 +fbfbfbfffffffdfdfdf0f0f0fffffffefefef3f3f3fffffff8f8f8fffffffffffff3f3f3 +f3f3f3fffffffcfcfcfbfbfbffffffe7e7e7fffffffffffffffffff8f8f8fafafaffffff +fefefefafafaf5f5f5ffffffffffffffffffffffffedededf3f3f3ffffffeeeeeeffffff +fcfcfcfffffffffffffffffffcfcfcffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbf5f9ebfcfff3f4faeefcfffafcfffbeff4f0fcfffbfcfffafcfff6f4faec +fcfff4f6fcf0f7fcf6fcfffff7fafff5f6fbfffffff8f8f8f9f9f9fffffffafafaffffff +ffffffedededfffffffffffff6f6f6f7f7f7fffffff9f9f9fdfdfdfffffffffffffcfcfc +fffffff8f8f8fafafafafafafffffff7f7f7fffffffffffff8f8f8e6e6e6fffffff8f8f8 +fffffffafafaf3f3f3fffffff0f0f0fffffffffffff6f6f6f5f5f5ffffffffffffffffff +fffffff7f7f7f6f6f6fffffffffffffafafaffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff3 +1e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddfecedddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddefecddefebdfefebdff1ebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeece0efebe0eeece0eeece0eeecdfecedddeceddbeceddd +eeecddeeecdfeeecdfeeecddeeecddeeecddeceddbeceddbecedddeeecddeeecdfefebe0 +efebdfeeecdfeeecddeeecddeeecddeeecddeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeece0eeecdfeeece0eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdde9eed7edf1d8f3ecd9 +f1eadaeff0e0e6ebe4e6eff89498a3fdf9fafffef4fdfce8fdfff9f8fdfff4f4ffc8bdf9 +cebfffc3bcffbcb9fccfd0ffeaedfff8fffff7fffff9fffffbfffff5f9fafbfdfcfffff6 +fffff6fffffbf7f7f7fffffff3f3f5fffffff3f3f3fffffff3f3f3fefefefffffff5f5f5 +fffffffdfdfdfffffff9f9f9fafafafffffffffffffafafafffffff8f8f8ffffffffffff +fafafafbfbfbfffffffcfcfcfffffff8f8f8f8f8f8fffffffffffff7f7f7ffffffffffff +fffffffffffff5f5f5fffffff6f6f6f5f5f5fffffffcfcfcfcfcfcfdfdfdfffffff6f6f6 +fffffffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffff9fffdeef9f1c7cfc2000200000100080806000106000107000407000407000d0b +000504000607f0f3f8fffdfffffdfffffdfffffffffffffff3f3f3fffffffffffff2f2f2 +fffffff8f8f8fffffffffffff7f7f7fffffffffffffbfbfbfffffffffffffefefeffffff +fffffffffffff5f5f5f8f8f8fffffffbfbfbfdfdfdfbfbfbfffffff8f8f8fbfbfbf7f7f7 +fffffffffffffbfbfbfffffff3f3f3fdfdfdfffffffffffff8f8f8f8f8f8fffffff7f7f7 +fcfcfcfffffff7f7f7fffffffcfcfcffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bc +e2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff1ebdff1ebdff2eaddf1ebddf1ebddf1ebddefecddefecdd +eeecdfeeecdfeeece0ecece2eeebe2ecece2ecece4ebede0e8f0dbe8f0d9ebeedbeceddf +eeece0efebe0efebdfeeecddeceddbebeed9ebeed9ebeedbeeecdfefebe2f2e8e6f2e9e4 +efecddeeedd9eeeddbeeeddbeeeddbeeecddeeecdfeeecdfeeece0eeece0eeece0eeece0 +eeebe2eeece0eeebe2eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeedd9ebefceeef3caeff1c9edefca +eef2d9e6ece0e9eef194999ffcfffffcfffbedf8e7f8ffffbbc0f8b0acff1b0ab21300c3 +1404c91004be03009fc4c5ffbecbf7f2fffff1fcfef9fffff7f6fffffdfffaf8e1ffffe4 +fffff3eeede9fffffdfdfffefffffff6f6f6fffffff9f9f9f7f7f7ffffffffffffffffff +f8f8f8fffffffbfbfbfffffffffffff6f6f6f5f5f5fffffffffffffdfdfdfefefefcfcfc +fffffffefefef4f4f4fffffffdfdfdfdfdfdfffffffffffff4f4f4fffffffffffffbfbfb +fcfcfcfdfdfdf4f4f4fffffff2f2f2fdfdfdfffffff9f9f9fffffff3f3f3ffffffffffff +fbfbfbfffffffffffff4f4f4ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffff +e6f8fff1ffff808a81c3c5b70700000400070201235159874058864c6f974b728f00081c +f1ffff020111f9e7f5fff7fffcf6fafffffff6f6f6fffffff9f9f9fffffffbfbfbffffff +fffffff5f5f5fffffffffffffcfcfcfffffffffffffbfbfbfffffff4f4f4fffffffcfcfc +f6f6f6ffffffedededfffffff8f8f8fffffffcfcfcfefefefffffff9f9f9ffffffffffff +fafafaf4f4f4fffffffffffff6f6f6fffffffffffffafafafbfbfbfffffffdfdfdfdfdfd +fdfdfdf5f5f5fffffff9f9f9ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8ff +f4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1ebdff1ebdff1ebddf1ebddefecddefecddefecddeeecddeeecdf +eeecdfecece0ecece2ecece2ecece4ebece4eaeee0e7f1d9e8f0d8ebeedbeceddfefebe2 +f1eae2f1eae0efecddeceddbebefd8ebefd8ebeed9eeecddf1eae2f3e7e7f3e8e6efebdf +eeeddbeeecddeeecddeeecddeeecdfeeecdfeeece0eeece0eeece0eeebe2eeebe2eeebe2 +eeece0eeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefecd9edeeceeef2cdedf1ceeaefd1edf2dc +e6ece0e9efeb929a9cf1fafff7fffff5ffffc4ccfd101070221daf0700bc1606e20400d4 +140adc0804bd1213a90d1578a2aee8f4ffffebf1fffffbffede5f4fffdebfcf7daffffef +fffff8fafafcfefffff6f6f8fffffffefefefffffffffffff2f2f2fafafaffffffffffff +fbfbfbfefefef4f4f4efefeffffffffffffffffffff5f5f5ffffffffffffffffffffffff +fbfbfbfffffff7f7f7ffffffe5e5e5fffffffafafaf6f6f6fffffff2f2f2f9f9f9ffffff +fefefefffffff6f6f6fffffffafafaf7f7f7fffffffdfdfdfffffffffffffafafaf6f6f6 +f9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff1ffff +f1ffff0003008b877bd5c7c407000900002500003a4e68b3355ba4325f9600072eedffff +f3f5ff2d1925ffebf3fffcfffffffff9f9f9fffffff8f8f8fffffff3f3f3ffffffffffff +f9f9f9fffffff1f1f1ffffffffffffecececfffffffffffffffffffefefefffffff9f9f9 +f8f8f8fffffffafafafcfcfcfffffffdfdfdfffffffffffffefefef6f6f6f8f8f8ffffff +fffffff0f0f0fefefeffffffecececfffffffbfbfbfffffff8f8f8f6f6f6ffffffffffff +fffffff8f8f8fcfcfcffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2 +e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddecedddeceddfeceddf +eceddfecece0ecece0ecece2ecece2ebede0ebeed9ebeed9eeecddefebdff2e9e2f2e9e2 +f2e9e0f1ebdfeeedd9eceed8eceed8eceed8eeeddbf1eae0f2e9e4f2e8e6efeae4eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeece0eeece0eeece0eeecdf +eeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefecddedecdaeeefe1edeceaeaeaecedefece6ebe5 +e9f0e8929b98f8fffff0f4ffb7b7ff00007f1510a807049df0efffe7e6ffeeefffeeefff +edf2ff0b119d0100b10a06a1c8ccfff7fcffede9fffff9fffff5fdfffef6fffff1fbfbf1 +f9f9fff8f7fffffefff8f8f8fffffffafafaf6f6f6fffffffcfcfcfffffffbfbfbfafafa +ffffffffffffffffffe5e5e5fafafafcfcfcffffffebebebfdfdfdfefefef9f9f9ffffff +f2f2f2fffffff2f2f2fffffff9f9f9fffffffafafaf7f7f7fbfbfbffffffffffffffffff +edededfffffff9f9f9fefefefffffffffffff0f0f0fffffff2f2f2fffffffffffffafafa +fbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffbf3fef0fbfff4 +0301000c02008a7b74d2c3ca120b2d00003e4855b35169cb3655a5001147ecfffff8ffff +f7f1f1080000fffefdf7f7f7fffffff7f7f7fffffffffffffffffff9f9f9fefefefdfdfd +fafafafffffffcfcfcfbfbfbfffffff4f4f4f4f4f4edededfdfdfdfafafafffffff2f2f2 +f2f2f2fffffffffffff4f4f4fffffffcfcfcf9f9f9ffffffffffffffffffeeeeeeffffff +fffffff7f7f7fdfdfdfffffffbfbfbfffffffefefefafafafffffff2f2f2efefeff5f5f5 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eada +ebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecdfecedddebeeddebeeddebeeddecedddecedddecedddecedddeceddfeceddfeceddf +eceddfeceddfecece0eeece0eeecdfeeeddbefecdbf1ebdff2e9e0f3e8e4f3e8e4f3e8e2 +f2eadfefecdbeeedd8eeeed6eeedd8efecd9f1ebddf2e9e2f2e8e6efeae7eeeae7eeeae7 +eeeae7eeeae7eeebe6eeebe6eeebe4eeebe2eeebe2eeece0eeecdfeeecdfeeecddeeecdd +eeecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebe0edeae1f0ecebede9f8eae8f6eeedf2e6ebe5e9f1e6 +919c96f1fbfff5f9ffaba6ff3025e50d03c4dcd9ffeef4ff0f1b71071168000968e3eaff +dcdfff1b10f0150cd9acaefff8fafffef9fff4ebfffdf3fefffdfafdfbecf7f9eefefdff +fcfdfffcfcfff2f2f2ffffffeeeeeefffffffffffff0f0f0fcfcfcfffffffefefefefefe +ffffffeeeeeefffffffffffffffffffafafafafafafffffffffffffffffffbfbfbffffff +f2f2f2ffffffe6e6e6f8f8f8fffffffbfbfbf8f8f8fffffff0f0f0fafafaecececffffff +fffffffffffffffffffafafafffffffffffffffffffbfbfbfdfdfdfffffffcfcfcfcfcfc +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffdfcfff6f8faef070300 +100900080000080000fffcffb2b7e14f5ba54256ac4c65b500024100032700031700020c +050a0efefffffdfdfdfffffffffffffdfdfdf2f2f2fbfbfbffffffedededfffffffcfcfc +fffffffffffffffffff2f2f2ffffff0a0a0a090909ffffffedededf2f2f2ffffffffffff +fffffffcfcfcfdfdfdfffffffffffff8f8f8fffffff3f3f3f1f1f1fffffffffffffafafa +fffffffefefeffffffeaeaeaffffffffffff000000fbfbfbfffffffffffffffffff4f4f4 +fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dc +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdf +ebeeddeaefdbeaefdbeaefdbebeeddebeeddebeeddebeeddecedddecedddeeecddeeecdd +eeecddeeecdfefebdfefecddf2ebdbf3e9ddf3e9e0f3e8e4f5e7e6f3e8e6f3e8e4f2e9e0 +f2ebdbf1ecd8f1ecd6efedd6f1ecd8f1ebdbf1ebdff1eae4efe9e9eee9edeeeaebeeeaeb +eeeae9eeeae7eeebe6eeebe4eeebe2eeebe2eeece0eeecdfeeecdfeeecddeeecddeeecdd +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebe0eeeae1f0ecebede9f7eae8f3eeefeae6ece0e9f0e8919c98 +f5ffffb9bffb160eb90000d30d02e2110fc8ebf5ffebfcffecfeffedfaffedeeff0a06cf +0500e50600ca0d0d7fc7c9fff3f0fffffbfffffefbfffeedfdfeec00020000000b030615 +0f1015fdfdfdf1f1f1ffffffe8e8e8f0f0f0fffffffffffffbfbfbfffffffffffff8f8f8 +fffffffffffff0f0f0fffffffffffffffffffdfdfdffffffefefeffafafa020202050505 +fcfcfcffffffffffff000000060606fffffffffffffffffffffffff8f8f8fdfdfdffffff +edededf6f6f6fffffff5f5f5f9f9f9f5f5f5fffffffbfbfbebebebfffffffffffffbfbfb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffefffefcfff9f8ff020200000300 +000300ccd4c5e5f2ebf2ffffb9d0de6b86a4506ba03350924a67ad4d6bab46659100041c +f4fdfffcfcfcfffffff5f5f5fdfdfdfffffffffffff7f7f7fffffffffffffafafaf0f0f0 +fffffff2f2f2ffffff000000fffffff9f9f9fafafafffffffefefefcfcfcffffffefefef +fffffffffffffffffff4f4f4fefefefffffffffffffffffffcfcfcfffffff1f1f1f9f9f9 +fffffffafafafffffff0f0f0ffffff141414f8f8f8f8f8f8fffffff9f9f9fefefeffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddebeedb +eaefdbeaefdbebeedbebeeddebeeddecedddecedddeeecdfeeecddefecddefecddf1ebdd +f1ebddf1ebddf2eaddf5e9ddf6e8dff5e7e4f5e7e7f3e7e9f3e7e9f3e7e7f3e8e2f2eadd +f2ebd9f2ecd6f2ecd6f1ecd8f1ecd9efecddefebe0eeeae7eeeaebeeeaebeeeae9eeeae7 +eeebe6eeebe4eeebe2eeebe2eeece0eeecdfeeecdfeeecddeeecddeeecddeeecddefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeeadef1ece6efeaf0ebe9eceef0e2e6eddde9efef919a9fe7f6f3 +cdd6ff1109be0000d11b11fb0e0dcb000874eafeff0f214fd7e5ff0d0fa01d1add0000da +1c14e31d1ba0afaff9fcfbfff8f8f8ffffefffffea010200fefffafbffffeff3fcf2f3f7 +fcfcfcfffffff5f5f5ffffffffffffffffffeaeaeaffffffffffffedededfffffff4f4f4 +fffffffffffff8f8f8f3f3f3fffffff5f5f5fafafafffffffbfbfb020202000000fdfdfd +ffffffffffff000000000000fffffff2f2f2fdfdfdf8f8f8fffffffffffffcfcfcffffff +fffffffbfbfbfffffffffffff3f3f3fffffffffffffffffffffffffefefef8f8f8ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffefffefafff8f5ff0b0e15000300becec1 +c9dcc9f2fff1efffefe0f9e4bcd6d55c73935870ac405baa3455a438629e00062cf2feff +fffffff7f7f7fffffff8f8f8fffffff0f0f0fffffffbfbfbe6e6e6ffffffffffffffffff +fcfcfcf8f8f80a0a0af6f6f6fffffffffffff7f7f7fffffff9f9f9f9f9f9ffffffffffff +fffffff2f2f2fffffffffffff3f3f3f3f3f3fcfcfcfffffff7f7f7fffffffcfcfcfafafa +fcfcfcefefeffffffff2f2f2060606f3f3f3fafafafefefeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddeceddbebeed9 +ebeedbeceddbecedddecedddeeecdfeeecdfefebe0efebdff1ebdff1ebdff2eaddf2eadd +f2eaddf3e9ddf6e7e0f8e6e2f6e6e7f3e7ebf2e7edf2e7edf2e7ebf2e8e6f3e9e0f3eadb +f3ebd8f3ebd6f2ebd8efecd9eeeddbeeecdfeeebe2eeebe4eeebe4eeebe2eeebe2eeece0 +eeece0eeecdfeeecdfeeecdfeeecddeeecddeeecdfeeecdfeeecdfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddf0ebd7f1eedbefece3ebebe1eef2d9e6eddbe7edf99099aaf4ffffb2beee +0804b31407f40700e2080abfe7f9ffe9ffff0f1e63edf9ffedf6ff0000801712e20000c4 +09049fcacbfffbfffffaffd8ffffe61b1c0af5f6f1fcfffff9fffff8fffff8f9fbffffff +f3f3f30000000b0b0b000000efefefffffff0000000f0f0f000000ffffff121212000000 +f9f9f9ffffff0909090c0c0c000000000000fcfcfcfefefe000000ffffff000000f4f4f4 +000000ffffff000000fffffff9f9f90c0c0c0d0d0d000000f8f8f8fdfdfd000000050505 +000000000000f1f1f1fffffffbfbfbffffffffffffefefefffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffebe6edfffdff00001300061685989cb5cdc0 +a8c1a3f4ffe4f7ffecebf8efc2cde1818eba465a97506fb2365f9f000636f2fefff9f9f9 +ffffff000000fcfcfcffffffffffff000000ffffff030303121212000000000000ffffff +ffffff000000040404050505fefefef4f4f40000000e0e0e000000f8f8f8fefefe000000 +ffffffedededf6f6f60d0d0dffffff0000000000000b0b0b000000fffffffafafaffffff +000000070707090909000000fffffffffffff9f9f9eeeeeefffffffdfdfdffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddeeeddbeeedd9eeeddb +eeecddefecddefebdff1eae0f1eae2f1eae2f2e9e2f2e9e0f2e9e0f3e9e0f3e9dff3e9df +f5e8e0f6e7e2f6e6e6f3e7ebf1e7efefe7f2eee8f2efe8eff1e8ebf2e9e4f3e9dff5e9db +f3ebd8f2ebd9efecd9eceddbebeeddeeecdfeeecdfeeecddeeecddeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeecddeeecddeeecdfeeece0eeebe2eeebe2efebe0efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecdbf0ebd5f3eed8f0ece0ebecdeeef2d7e6ecdee7ecff9097b3f4ffffbbc7f90a05b7 +1208f40100d9e9ecff03176ee9ffffe7f3ffeef8ffe7f6ffebf6ff120ed41007de0903a5 +bebefff9fff8ffffd6fcffe2010100fffffff5f8fff8fffff8fffffefffffafafaffffff +fffffff5f5f5ffffff040404ffffff000000fbfbfbffffff000000f6f6f6ffffff000000 +ffffff000000fffffffbfbfbffffff000000ffffff010101f6f6f6070707ffffff000000 +ffffff000000fffffffffffffafafafafafaffffff000000f9f9f9060606f9f9f9ffffff +ffffff0d0d0df1f1f1fffffffafafafffffff0f0f0fffffff6f6f6ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffdfffefbf0edf6070a2d4e57824e5e80708694c6dace +bccab1f4f9e5fffffafef7fff1efff7e85b94357964a6bb200023af7fffffffffff8f8f8 +050505fbfbfbfffffffcfcfc000000fdfdfd050505f9f9f9eeeeeeffffff000000f8f8f8 +060606fefefefafafaffffff060606fffffff6f6f6fdfdfd000000ffffff000000ffffff +fdfdfdffffff000000ffffff010101ffffffffffffededed0e0e0effffff000000ffffff +fafafaffffff000000fdfdfdf6f6f6fffffffbfbfbfffffffafafaffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddf2ecdce6dfcdf7f0e0fdf5e8 +f3eae1f5ece5ebe2ddf4ebe6f1e7e5f3e8e6f4e9e7f2e7e3f0e5e1f0e5e1f2e9e2f6ebe7 +fceeeef3e7ebe6dfe7eae7f2f2f1ffeaecf9e6e6f0f2eff6f3eaebf7ece8f9ece3f4e8dc +ebe5d5e7e5d6e8ecddedf1e0f2f4dfeaead2f3f3dbe9e9d1f0f0d6f4f4dae7e7cde7e7cf +eeedd8eeedd9eeeddbeeecdfeeece0eeebe4eeebe6eeebe6efebe0efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdd +f0ebd7f3edddf0ebe5edeae3eff0dee8ebe4e9eaff9195b8f2ffffc0c9ff1108c30100e6 +0a02e3e9edffe6fcff0b23510813631c2574edffffecf8ff0000c01206e209029dc3c1ff +f9feffffffeafcfdef010000fffefff5f7fff8fffff8fffff7f8fdffffffffffff000000 +0000000d0d0d000000ffffff000000fbfbfbffffff050505f8f8f8ffffff000000fefefe +000000fefefeffffffececec0c0c0cffffff000000fffffffbfbfb030303fefefeffffff +080808f2f2f2ffffff000000020202000000060606ffffff000000fffffffbfbfbfefefe +000000fffffff7f7f7fffffffffffff4f4f4fafafaffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffdfffef8fffcff00002e5357a1565fac00003c8089aac7c9d6 +d0c5cb0d000210000cfff1ffd4cafe5758994554a500084bf9fefff6f6f6ffffff090909 +f9f9f9f8f8f8ffffff000000ffffff000000fcfcfcfffffff4f4f4050505fafafa010101 +f6f6f6ffffffffffff000000fffffffcfcfcffffff000000f8f8f8010101fffffff6f6f6 +ffffff000000fbfbfb010101f7f7f7ffffffffffff000000ffffff010101fefefeffffff +fdfdfd030303fffffffcfcfcf4f4f4fffffffbfbfbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc7 +0837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff1ebddfaf1e2f7ebddf4e8dce5dbd1eadfd9 +fbf0ecf4eae9eee4e5f5ebecf4e9edf2e9ecf4ebeef7eeeff4eeeeeee9e6e8e2e2bab4b6 +c2bdc4bfc2cbb7bdcbacb5c6a8b4c4c0c7d7e5e7f3e7e2e9e8dedfecdeddf2e7e1f8f1e7 +f5f5e9eaf0e4e2e8dae5e7d1f5f5dbf3f3d9f1f1d5ededd1f8f8dcefefd3f7f7ddeeeed6 +eeedd9eeeddbeeecdfeeebe2eeebe6eeeae7eeebe6efebe2efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1e9dc +f3ede1f2ebe3edebdfeff1dce8ebe4e9eaff9195baf5ffffabb4eb0c04af1a0df00901de +0505bde7f4ffe0edfff0f4ffd7daffeef9ff0d13850800ce2215e8100d8ec0c1fffcfdff +fafaf8fffdff1b191ef5f4fafcfffff9fffff8fefffefffff0f0f0000000ffffffffffff +ffffff000000ffffff0e0e0efffffff1f1f1050505fbfbfbf9f9f9020202fcfcfc080808 +fafafaffffffffffff000000fefefe080808f8f8f8ffffff000000f9f9f9fbfbfb000000 +ffffff000000fffffffafafaffffff010101efefef0c0c0cffffffe9e9e9ffffff0e0e0e +fffffffffffff3f3f3f6f6f6ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbf9fcf3f3f8fe010b3c414e9c4555b45d6cc700003f72759ec5bece +88797e0d0004fff5fffff4ff5657905a66ae000039f4f9fffffffff7f7f7000000ffffff +fffffff4f4f40a0a0af3f3f3000000ffffffffffffffffff040404ffffff000000ffffff +fffffff4f4f40b0b0bf7f7f7fefefef0f0f0000000ffffff080808fbfbfbfffffff2f2f2 +000000ffffff000000ffffffecececffffff030303f3f3f3080808f8f8f8fbfbfbffffff +000000fefefefffffffffffffffffff5f5f5fefefeffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db +1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff1ebddeee2d4f8eaddf7e9e0f2e5ddfbf0ecf7edec +f3eaedefe8eff6eff7ded9e0bfbcc5aeadb5afb0b5b6b9bebdc1c4bfc3c6b6b9beb9c0c8 +bac8d3b7cad9a7bed08fa5ba7b8ca0747d8eeeedfbf8f1f9fff2f9f9edefede5e3e2e3de +e3e9e5eaf1e9e9ecdbfdfce7dfdec9e3e3cbe3e3cbefefd5e5e5cbeaead0eeeed6eeedd9 +eeeddbeeecdfeeebe4eeebe6eeeae7eeebe6efebe2efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0f1e8e3f3ece4 +f2ecdcededd5eff2d3e9ebddeaeaff9295b4edf8fef4fdffd4d1ff0000a90800d30a00db +0e09d71611cdf1ebff1f17b80000a21c11d90700d90000adc2c3ffe4e8fffefafff9f3ff +fffbfffffaff010002fcfffff9ffffedf6f5f7f9f8ffffff000000ffffffeeeeeeffffff +000000f7f7f7000000ffffffffffff0f0f0ff1f1f1fefefe121212f5f5f5000000f5f5f5 +f6f6f6ffffff000000fcfcfc040404fffffffcfcfcfffffffbfbfbffffff1c1c1cf6f6f6 +000000fffffffefefefcfcfc000000ffffff000000fffffffffffff5f5f5000000dadada +fffffffffffffdfdfdfffffffcfcfcf7f7f7ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffbfffbf2fff8eaffff00081e567bb0476cc42648a94463b6000f488797a4c2cec2 +ccd2c6000202f7feff4a5982475f8d000c31f4fcfffffffffefefe020202f5f5f5ffffff +fafafa000000ffffff080808f3f3f3ffffffffffff000000fbfbfb020202fffffff0f0f0 +ffffff000000fbfbfbffffffffffff000000f7f7f7070707eeeeeef0f0f0ffffff000000 +f5f5f5000000fdfdfdfafafaffffff0a0a0afafafa0a0a0afffffffffffff7f7f7131313 +fffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff3 +1e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff1ebddf4e8dafceee1f7eae1f7ece6ede3e2b5acafb7b2b9 +c2c0cbb2b2beb4b8c4bdc5d2ccd6e2d5e2ebcfdde6bbccd3abbdc1a3b2b9889aa46f8996 +6d8e9f7ca1b48eb1c78ba7bd7d8da4868b9fafabbadfd3e1f6ebf3f3ecf3e8e8eae1e9eb +e4edecddded9f7f4ede8e6daf5f3e6fffff1f6f5e3edecd8f1f0dbeeedd9eeedd9eeecdd +eeecdfeeebe2eeebe6eeeae7eeebe6efebe0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0f0e8e6f3ece4f0eed5 +edefcaf1f3cee9ecd9eaebff9495b1f8ffffeef6ffb7baff1210970e04bb1e10eb0000da +0900e7f0dfff0a00bc1605e11100dd1607d21611a3c3c6fdf9fffff6f2fffff9fffff9ff +fff8fffdfbfe000200000400010c00000100ffffffffffff0000000707070000000b0b0b +ffffff000000fffffffdfdfd000000f9f9f9ffffff000000ffffff060606030303070707 +000000f8f8f8ffffff0f0f0ff7f7f7fcfcfcf3f3f3fffffff5f5f5000000ffffffffffff +000000030303000000121212ffffff000000020202000000101010fbfbfbffffffffffff +f8f8f8fcfcfcfffffffbfbfbffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +f8fffdebfffbdbffff000e2533629a1946a3436ddd3b61cc3456ad000432647f926d848a +bdd4dc00041ce9ffff4d6f95000523f8fffff5f5f5f2f2f2ffffff000000000000000000 +050505f4f4f4000000fcfcfcffffffffffff080808f7f7f7040404f9f9f9ffffffeeeeee +ffffff000000000000000000f8f8f8ffffffffffff000000131313000000000000ffffff +0a0a0afffffffdfdfdf1f1f1000000f4f4f4f9f9f90b0b0b000000111111000000f0f0f0 +fffffffffffff5f5f5ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bc +e2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1ebddeee5d6f6ece0ece3daf5eee8f5f1f0c0bfc4e1e4ede3e9f7 +d8e4f4c4d4e4a9bccd90a7b7819da97e9ca77fa0a982a3aaa6c3cbaeccd6bce4f0c2f1ff +b9ecffadddf48db2cd627c97bec8e3c0bed4beb2c8b9acbdb7afbeb5b5bfb2bbc4b3bcc5 +f0eefcf6f0feefe9f3e7e2e8f0eceddbd8d3e6e3daf6f4e7eeecddeeecddeeecddeeecdf +eeece0eeebe2eeebe4eeebe2efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0f0e8e6f3ede1f0f0ceedf0c3 +f1f3cbe9ecd7ecebfb9595adf9ffffedf7f6f7ffffc2c7ff0a05830100ac2412fc0e00f0 +f2dcff1600cd1100c90200a9120b97c2c4ffeef4fff0f7f0fffffaf5eff1fdf1fffff9ff +fdf8fcf6faebfbffe8fbffeafefff8f8f8f8f4f4f4fefefefefefefffffff9f9f9f1f1f1 +fdfdfdfefefefdfdfdfffffffffffff3f3f3fffffff7f7f7000000fffffff9f9f9ffffff +fffffff5f5f5fafafafffffffffffff6f6f6fffffffffffff2f2f2fffffff4f4f4fefefe +fffffffffffff8f8f8ffffff000000fefefefffffffbfbfbf5f5f5f9f9f9fbfbfbffffff +fdfdfdfafafaf3f3f3ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8ffff +e3fffde2ffff000b42476cc43c64d63f66e9375de63c5ee32f4dc5617fe1355497395a87 +c3e6ff0006295374a7000230eff6fffffffffffffffffffff5f5f5ffffffffffffffffff +fffffffefefefcfcfcfffffffcfcfcf4f4f4fffffffafafafffffff3f3f3fffffff5f5f5 +fdfdfdfffffffdfdfdfffffff3f3f3f9f9f9fffffffffffff4f4f4fffffffffffff7f7f7 +fffffffffffff9f9f9fffffffffffffffffff3f3f3ffffffffffffeeeeeefffffffbfbfb +ffffffffffffffffffe9e9e9ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8ff +f4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff2eaddfef8eae9e5dae4e1dce4e4e6b7bcc2d4dee895a5b47f94a7 +809bae86a5b98fb4c69ec8d8b2e0edc9f9ffd9ffffc0e8f0c3eef7ccffffc6ffffb1eeff +ade6ff97c6e26b8cabcbd8f8d2d1f0d6cce7d9cbe4d6cee3d3d2e2cad3e2c9d1e4b4b1d0 +a99fc2b7aecdc4bcd4e5deeefff9fff3eff0e8e5e0eeebe2eeecdfeeecdfeeecddeeecdf +eeecdfeeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebe0f0e9e3f3ede1f0efd0eeeec8f1f1d5 +eaeae0edeafb9795abf4f9fcf3fdf4f8fff8edf7fff5f9ffb9b6ff00009a2312d01200ae +1b0ca70c018cc8c4ffb5b6fff5fcfff9fffffcfff4f1eee7fffcfdfff4fffffbfffffefd +fafceff7ffeaf5feebfefffafffffffffffffffffffffffff3f3f3ffffffffffffffffff +fbfbfbf9f9f9f7f7f7fffffffffffff0f0f0ffffff000000f6f6f6fffffffcfcfcf8f8f8 +fffffffdfdfdffffffffffffffffffe6e6e6f5f5f5fffffff6f6f6ffffffffffffececec +fffffff7f7f7fdfdfd0e0e0efdfdfdfffffff2f2f2fffffffbfbfbf3f3f3f9f9f9ffffff +fffffffefefef9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff4ffff +ecfdff000337364a934c61ba3750b5405acb405bd0435cd2324eb14b6aad3e5e8745637d +47617c415587000732f9fcfffcfcfcfffffff8f8f8f8f8f8f6f6f6fffffff3f3f3f3f3f3 +f7f7f7fffffffbfbfbf9f9f9fffffffffffffdfdfdfffffff5f5f5fdfdfdffffffffffff +ffffffedededfafafafffffffffffff7f7f7fffffffffffff9f9f9fffffff5f5f5fcfcfc +fffffff9f9f9f8f8f8ffffffeeeeeefffffff3f3f3fbfbfbfffffffdfdfdfcfcfcf7f7f7 +f3f3f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2 +e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfe5e2d3f2f0e3e8e8deeef0ebf0f5f8c4cfd5e9f9ff869dadaac6dbadd0e4 +b4dff2bbeafcbcf1ffbcf6ffbffbffc2fcffdbffffccfeffc0fbffadf0ff9ce3f9a6e8ff +96cbea6286a8dcecffe8e8ffeee5fff0e3ffebe3fbe7e5fbe2eaffe5ecffeae4ffb8abe3 +9084b6766b95766c8ef1e9ffefe9f5ede8eceeeae7eeebe2eeecdfeeecddeeeddbeeeddb +eeeddbeeecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff0e9dff3ede1f0eddceeeadef1edeaeae7f0 +ede9ff9795adfcfefffbfffff9ffeff1ffe8f8fffdf5fdffc4c7fcbcbdfebab9f3c3c4f2 +c2c9e6f4fcfff7ffffe9f4faf6ffeefcfff2fffaffefe3f9fffbf2fcf5e2fffff4fffffd +f7fafffcfefffefffff1f1f1f9f9f9fffffffffffffffffff6f6f6f3f3f3eeeeeeffffff +fffffffffffffdfdfdfffffffffffffefefefdfdfdfffffff7f7f7efefeffffffffafafa +fffffffffffffbfbfbfffffffffffffffffff7f7f7fffffffffffff7f7f7ffffffffffff +fffffff6f6f6fffffffefefef7f7f7fffffff5f5f5fffffffffffffffffff8f8f8f9f9f9 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffdeefffff6ff +0a00070d030c04000c0304190000220e153f000b2e00031b00050b0b1b1b00030500000c +080120010017fffdfffffffff3f3f3fffffffffffffffffff6f6f6ffffffffffffffffff +f9f9f9fffffffbfbfbf8f8f8f3f3f3fffffffafafafffffffffffff2f2f2f4f4f4fafafa +ffffffffffffffffffefefeffffffff7f7f7ebebebfffffffefefeffffffffffffeeeeee +ffffffffffffeeeeeefffffff6f6f6fffffffefefefdfdfdf4f4f4ffffffffffffffffff +fdfdfdfcfcfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001bc70837db1c60f31e55bce0e9fff4ebe2e8ebda +ebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeeecdfebeddfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff4eee0efecdde4e4d8eff4ede0eae9a6b5bae2f5ff89a5baa7cce6a5d4f0a3dffb +a7e9ffaaf1ffaef6ffb3f7ffb8f8ffbaf3fab4eff7b4f8ffa9f2ff99e5ffa8edff9ad2f5 +638bafbbcdf3c8caf0ded4f7f6e8fffef4ffe3e2ffb1b7db888fbb726caa786cae7e73af +756b9d4a4267f5edffe9e3eff0ebefeeebe6eeebe2efebdfeeecddeeeddbeeeddbeeeddb +eeeddbefecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeeadef1ede1f0ece3eee9e6f1ecf3ece5f5eee9fd +9895a8f6f5fffcfffff4fde8f3ffe0f8ffe6f7ffebf2fff5f8fffff7fff8fbfff4f9ffec +eefce3f7fff7f9fff8faffebfdfff4fbf3fffff9fffcf6e8ffffe8fffff4edecf1fcfdff +fbfcfffdfefffffffffffffffffffff5f5f5f8f8f8fffffffffffffffffffffffff6f6f6 +fffffffffffffbfbfbfffffffcfcfcfffffffffffff7f7f7fffffffffffffdfdfdf8f8f8 +fdfdfdffffffedededfffffffcfcfcfffffffbfbfbf7f7f7ffffffffffffedededfcfcfc +fffffff6f6f6fffffffffffffafafafffffffffffffafafafdfdfdffffffffffffffffff +f9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcfffff5ffffebfffff8f4 +fffaebfff7e7fffdf1fffefbeeeef0f7fcf8f9fff8f5ffeffcfff3fffffafffcfffff9ff +fff9fff9f4fafffffffffffff9f9f9fffffffafafafafafafffffff9f9f9fffffffcfcfc +fffffffffffff7f7f7fffffffefefefdfdfdfffffff2f2f2fffffffffffffdfdfdf5f5f5 +fffffff8f8f8fffffff1f1f1fffffffefefefffffffafafafcfcfcfdfdfdfcfcfcffffff +f1f1f1fffffffdfdfdfffffff8f8f8fffffff2f2f2fffffffefefef4f4f4ffffffffffff +fdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001ec90534d81d61f42158bfdde6fff4ebe2ecefdee9eeda +eeeddbefebdfefeae4f1eae4f5e8dff5e9dbefebdfeceddfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff2eadd +ecded1fceee1ece9dae3e7d9eef9f1aebdc0c7daeb93b1cda1cef595d4ff8ee1ff90edff +94efff98edffa9edffb5f3ffb3f0f5adeef4a8f0ffa7f3ff96e2ff9adfff97cdfb6086b3 +abbce7b8b7dfc4b8e0c2b1db9e92c27c77ad7476b36d70b36e6ab4746db1756da8726c98 +524e69eeeaf8f0ecede9e6dfefebe0efebdff1ebdfefebdfefecddefecddeeecddeeecdd +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfedebdef0eee1efece3edeae3f1edecece7ebf0ebf299969d +fffefffeffff7b81777f8877838f7978866f7b8a7782917e818b7390997e6e775a828a72 +a4ab99fefff3fffff3fffff8fbf6fdfffafffffefbfffffafffffff6f7fcfcfffff0f3fc +fefffffafafafdfdfdfffffff4f4f4fffffff9f9f9fffffff8f8f8fffffffbfbfbffffff +f7f7f7f9f9f9fefefefffffffdfdfdfefefef9f9f9fffffffbfbfbfffffff8f8f8fbfbfb +f6f6f6fffffffffffffffffff6f6f6fffffff7f7f7fffffffbfbfbf7f7f7fffffff2f2f2 +fffffffafafaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffefffffcfffffbfffffdfbfffef8 +fffef8fffffafffffdfffffffefffffefffdfefffbfefffbfffffdfffefffffdfffffdff +fffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff2eaddf6e4da +fcecdff1eeddebefe0e6f2e8cbdbdbb6c7d7a4c1df93c2ec8ad1ff84e1ff82eaff84ecff +8febffa2ebfeacebfaa9eef5a3ecf59be9fd9becff8cddff92dcff95cfff668ebfa4b7e2 +b8bae3c4b9e3bfafdc988bc1736dab6f72b96f72bf7976c37a77bc7772aa706e95504c63 +ecebf3f3efecefede1f1ebdff1ebddf1ebdff1ebdfefebdfefebdfeeecddeeecddefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfedebdcf0eee1efede1edeae1f1eee9ece8e7eeeced99979affffff +feffff868887e5eae4eaf1e9e3eee0d7e4d3e0eddbe4edd8d4ddc8fcfff1e7ebdc8f9385 +494b40fffffafffdfafffefdfffefffffdfff4f3f8fdfefffeffffdee2e5fefffff9f9fb +fffffffdfdfde1e1e1fffffffffffffbfbfbffffffffffffffffffedededfefefeffffff +f5f5f5fefefef9f9f9fcfcfcfffffffffffff5f5f5f6f6f6f9f9f9ffffffffffffffffff +ffffffffffffe8e8e8fffffffffffff6f6f6f9f9f9fcfcfcffffffedededffffffffffff +fffffff3f3f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff2eadff7e9e0f4e7de +f2f0e1eff6e6dee8ddeaf6f4a7b5c2b8d2ed85b1d687c8f281ddff7be2ff7de2ff8ae6fd +9ce5f89ee3f29be9f392e8f588e2fa87e4ff7ed9ff86d8ff8ed0ff6c9ccc91acd7b4bde6 +c0bbe4bdb1df978ec37170ac767ac17b81cb9292dc908dd08681b977759c524e65ebeaf0 +f2eeebeeece0f1ebdff1ebddf1ebdff1ebdfefebdfefebdfeeecddeeecddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddeeebdaf1eeddf0eddeedebdff1eee9eae9e7ededef98979cf6f7fcfefeff +727378feffffeef2f5fcfffffcfffffcffffe5edf0f9ffffe8edf1fbffffa6aaadfeffff +4c4c4efffefffffefff8f6f7fffefff9f9f9fefffffefffffefffff7f9f8fffffffdfdfd +fffffffffffff7f7f7f5f5f5fcfcfcfdfdfdffffffedededffffffffffffecececffffff +fffffffffffff9f9f9ffffffeeeeeefffffffffffffffffffffffffefefefffffff7f7f7 +fffffffffffff9f9f9eeeeeeffffffffffffffffffffffffffffffe3e3e3fefefefbfbfb +f8f8f8fbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdff4e7dff0e6ddebecde +ecf3e3e2eaddeffaf6aab4bebfd3eb7da5c882c2e880d8fe74dbfe73daf982e2fb92e0f7 +8edbef8ae3f384e5f879defc79dfff75d7ff78d2ff83ccff6ea3d57fa0cdb0bfe8babce5 +beb8e4a09ccf7a7bb48489cb888fd79090d8918fd08984ba7a789d535065eae9eff0ede8 +eceadef1ebdff1ebddf1ebdff1ebdfefebdfefebdfeeecddeeecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecddf0ebd7f3eedaf0eddcedebdeefefe7e9e9e7ecedef95989df7faffeef0fc888795 +fffdfffffdfff2eefcfffcfffffcfff9fdfff7fefff0f5fff8fdff9699ac393b4a61616d +45444cfdfcfffffefffffffffffffdf2f4f1eef0ebfefffbfdfffcfdfdfdfffffff4f4f4 +f4f4f4f9f9f9fffffffdfdfdfffffffffffffffffffdfdfdf8f8f8f6f6f6ffffffededed +fffffffffffffffffffffffffffffff6f6f6f3f3f3f9f9f9fffffff9f9f9ffffffeaeaea +fffffffffffffefefef0f0f0fbfbfbefefeff5f5f5fffffffffffffafafafffffff4f4f4 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001ec90435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff1eae0f0e5dff1e8e1e7e7dbe8ecdd +ecf2e4e6ebe5c4c8d1bbcadf7fa2c282bee37bd3f96dd5fa6ad7f876ddfc86dbf880d6f1 +77ddf675e2ff6adaff6eddff6cd8ff6bccff75c5fa6aa8db7298c5aec3eeb4bbe5babbe7 +a6a4d67a7bb38186c68186ca7372b67978b47b77a9757496535063ebeaeff1eee9edebdf +f1ebdff1ebddf1ebdff1ebdfefebdfefebdfeeecddeeecddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdb +f1ebd5f4eed8f2eddaedebdeeeefe7e8eae7e9eef19299a1fbfffffbfeff8f8da2fffbff +7369819e90a988768e7e70918989bd6b71ab7b81b5767aa7868aaf0a0e29d3d4e852525e +fffefff0f0f0fffffbf7f8f2fffffafffffaf2f5eefefffbfbfbf9f8f8f8fcfcfcffffff +fffffffffffffffffff3f3f3f8f8f8ffffffe8e8e8fffffffffffff1f1f1ffffffffffff +fdfdfdf1f1f1ffffffe1e1e1fffffffffffffffffff7f7f7f9f9f9fffffffffffff4f4f4 +f4f4f4fffffffdfdfdfffffffffffffffffff3f3f3fffffffffffff1f1f1ffffffefefef +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001ec9 +0435d81d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff1eae0f0e7e2f4ebe6e9e9dde8eadcf4f6e8 +e1e4dde2e3e8b5c0d285a6c57ebadf71caf463cef85ed2fb67d7ff73d5fc70d2f766d4f9 +69ddff60d5ff64d8ff66d3ff60c3fc6abcf46aa9de6893c0b0c8f4b1bae5b7bae5a3a4d4 +7071a7767ab77377b67272b27a79b37e7ba8787796545162ebebedefece5ebe9ddf1ebdf +f1ebddf1ebdff1ebdfefebdfefebdfeeecddeeecddefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdbf2ead5 +f5edd8f2eddaedebdeeeefe7e5ebe7e6f0f1919aa1f1f9ffebeeff838196fffaff857590 +120019e4cae7221038030142000046161e5f00003514184500001ff7f9ff484a56feffff +fffffdf0f1ebfdfef6f2f3eb0001000002000001000b0b09f4f4f4fffffff3f3f3f3f3f3 +ffffffebebebfffffffffffffffffffffffffefefefffffffffffffbfbfbf5f5f5ffffff +fffffffffffffffffffffffffffffff7f7f7fffffffffffffffffffffffff7f7f7ffffff +ebebebfffffffafafaffffffeeeeee0f0f0ffffffff3f3f3ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001ec90435d8 +1d61f41f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff1eae0f4e9e3f1e8e1f1efe2ecedddebecdce9e9df +efeef3aeb9cb8aabcc77b5de60bfef54c8fb51cdff54d0ff5ecdff5fcdff58cafc61d5ff +56cbff5ccdff61cbff59b9f564b5ed6eabe15d85b6b1c9f5b1bae5b8b9e5a5a3d4706da2 +7d7eb68080bc8c8bc79090c68d8ab580809c565462e9e9ebeeebe4eae8dcf1ebdff1ebdf +f1eae0f1eae0efebdfefebdfeeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf4e9d7f7ecda +f3ecdcedebdeedf0e7e3ece7e5f1f18e9c9ff7fffff8feff908f9febe2f5a794aa2e152b +14000c280f371110540e1766081058040d480007350e1434f8fdff51545df0f2f1f3f6ef +fffff8f8f9f1101109fffffaf7f8f3fffffdfdfdfdfffffff5f5f5fffffffffffff3f3f3 +fffffffffffff7f7f7ffffffeeeeeefbfbfbf7f7f7fefefefdfdfdfffffff4f4f4ffffff +ecececfdfdfdfffffff6f6f6fffffffafafaf3f3f3fefefefefefeffffffffffffffffff +f8f8f8fffffffdfdfdffffff000000f4f4f4ffffffffffffedededffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001ec90435d81d61f4 +1f58bfdde6fff4ebe2ecefdee9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff1eae0f8ebe5ece2d9f5f2e3efeedae0ddcaf5f3e7efedf2 +acb4c78dafd271afde56b7ec4ac2fe45c9ff45c9ff4dc7ff55c8ff52c3ff5fcdff53c1fe +5ac4ff61c3ff5bb0f067afea76ade35579abb1c6f3b2bbe6bdbce8aaa7d67a73a6918cc2 +9b98cf9898ce9898ca918fb67f7f9953515ee9e9e9f1eee7f0eee2f1ebdff1ebdff1eae0 +f1eae0efebdfefebdfeeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf4e8d8f7ebdbf3ebde +edebdfedf0e7e3ede5e3f2ef8d9d9df0fbfff5fcff82828afffbff887480ffedfbfff3ff +ffeefff8f8ffdfebfff1fafff2fbffdce5ff00001bf9ffff3f4448fefffbfefff8fdfff4 +000200fffffaf9faf5fdfdfbfefefefffffff4f4f4ffffff030303040404000000ffffff +f5f5f5030303000000050505ffffff010101000000ffffffefefef0b0b0b030303000000 +040404fffffff8f8f8ffffff000000111111000000fffffffefefe000000fafafaffffff +fcfcfc020202ffffff000000000000000000fefefefffffff9f9f9ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff2eadff9eae3f3e5daf3ecdaedebd6e9e4d0f3efe4e9e4eab6bed3 +8fb1d75f9ed14fb3ef45c2ff3ac3ff38c2ff3bbaff4ec3ff4db5fc5bbcff5dbcff5cb8fb +55a8ec68afef609bd77face3607eb0a3b4e2c0c4f1b4b1dcb0a8d7837aa98f85b7a79fd2 +a4a2d4898ab87776988a8ba04d4b56f7f7f5e8e5dcedebdef1ebdff1ebdff1eae0f1eae0 +efebdfefebdfeeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdff4e8dcf7ebdff3eae1ebebe1 +ebf0e9e2ede5e3f2eb8d9e98f7fffff3fcf9868684fffdfb907e7cffefeefbdcda311b28 +f8fbffeefdff0a1648effbffe1ecff0d1627e2e9ef555b57fefff8fcfff4fffff6000100 +fffffbfffffff7f7f9fffffffafafcfffffff1f1f1fffffffefefef0f0f00d0d0dfdfdfd +030303f8f8f8ffffff010101fefefefcfcfc040404ffffff000000f8f8f8fffffffbfbfb +000000f7f7f7070707fffffffdfdfdf9f9f9040404ffffff040404fbfbfbfbfbfbffffff +050505fdfdfd000000fffffff6f6f6fdfdfdfffffffbfbfbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff2eadff8eae1eee0d3f3ebd8f7f2dcf2ebd8f7f1e5f6f1f7dbe1f99ebee7 +67a4da49abea35b0f42db2fd34b9ff35afff40adff59b5ff55a4ef519fe769b2f773b4f8 +7db4f5618ec97091c7a1b7e8bcc7f5b9bae6afa9d5bbb2dd9388b38e81af9087b4716e9b +9294bb7c7b9b7c7d91595860eaeae8e5e2d9f8f6e9f1ebdff1ebdff1eae0f1eae0efebdf +efecddeeecddeeeddbefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff1ebdff2e8def5ebe2f2ebe3ebebe3ebf0e9 +e2ede5e5f2eb8e9d96f7fffbf9fffa7f8078fffbf194867bfffaed34180a64504ff8fcff +0c1b42aab9da091731dae6f6000309f9ffff4a4f48fdfff5f2f6e8fffff60c0d07fefefc +f3f3f5fffefff8f7fdffffffe9e9e9ffffff000000030303131313000000fdfdfd030303 +ffffffeeeeee000000fffffff3f3f3060606ffffff000000fffffff7f7f7ffffff030303 +ffffff000000fffffffffffffafafa030303ffffff000000ffffffffffffffffff000000 +fafafa080808f2f2f2ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff2eadffceee3f1e4d4f3ebd6f8f3ddf0e9d6ebe4daf0e9f1eaeeff96b1dc558cc4 +419bda46b5fa42bcff3bb3ff3dabfa5dbaff59a0f074affd7eb6ff74a6ed5683c66a90ce +7996cea2b8eaa3b1e0bcc3efc1c3ecbab5deb8b0d9867ba58a7ea6988db7817fa7717497 +6969856d6f7e5e5d62edeee9fffff6dedccff1ebdff1ebdff1eae0f1eae0efebdfefecdd +eeecddeeeddbefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff1e8dff3ece4efece3eaebe3ebf0e9e3ede5 +e6f1e9919c94ebf7edfbfff6818375fffcec8d8270fff6e2fffbe425170af9ffffeffeff +4b5b6a4f5d66d6e1e5000400fbfffa4e5448fafdf2fffff6fbfcf4000100fffffff7f6fb +fefefffafbffffffffffffff000000fbfbfbfffffffbfbfb000000ffffff080808e5e5e5 +ffffff000000f1f1f1ffffff000000ffffff000000fffffff1f1f1fbfbfb000000ffffff +0e0e0ef1f1f1ffffffe8e8e80b0b0bffffff060606f7f7f7f8f8f8f1f1f1070707ffffff +010101ffffffffffffffffffe2e2e2ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f1ebdffbefe3f6eadcf3eedaf1efdaece7d4e7e0d6ebe1eae8e8ffa4b7e16795c94d99d5 +419fdf389ee040a3e655a9ef7abeff83b6ff759eee5276c24061a8617dbebdd1ffbacafe +9da7d8a2a9d5a2a5ce9ea0c7a9a7cebcb6dc8e86ab847a9d7b73987270958c8fb09797af +8d8f9c525254dbdcd6e8e6dafefceff1ebdff1eae0f1eae2f1eae0efebe0efecddeeecdd +eeeddbefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeeadff0ede4edede3eaebe3ebf0e9e5ece5e7f1e9 +929c94fbfffae9efe38e8f81ffffef7d7562e8dcc6fff0d7efe6d5d5dbdbecfbffd1dfe2 +ccd8d8f6fffd08120af9fff54f5247f7f9eef7f8f0fffffaf3f3f1000002fffefff9f9ff +fefffffffffff2f2f2000000fbfbfbfffffffdfdfd020202ffffff000000ffffffffffff +000000fcfcfcffffff000000ffffff000000ffffffffffffffffff000000fbfbfb000000 +fffffffafafaffffff000000ececec0d0d0dedededfffffffdfdfd020202eeeeee050505 +efefeffffffffffffffdfdfdf8f8f8ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9 +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdf +efe6ddf5ede2f0efddedecd8f1eeddf7f0e8f6ebf3eee9ffaab3da7898c75c95ca549bd1 +71baef97daff8bbef37096d45772bf6077c75e70bc5362a7656facbfc6fcd2d6ffc1c4ef +b7bbe1abafd4a2a5c8a2a5c6a8a9c87e7d9c7f7a987875949c9cbe888ca9bfc0d5989aa6 +565658ebece6fffdf1e0ded1f1eae0f1eae0f1eae2f1eae0efebe0efecddeeecddeeeddb +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecdfebecdeedefe1eceee3e9ece3ebf0e9e6ebe5e9efeb949a96 +f9fef8f6f9f287877ffffff4140e00261f0f08000004010009100900040016211b000601 +000300040902f6f9f25c5d57fffffafffefaededebfffffffeffff040509090a0f000005 +0c0c0ef4f4f4ffffff0606060000000000000d0d0df9f9f9121212fdfdfdededed000000 +fffffffefefe000000ffffff000000000000000000202020ffffffffffffffffff000000 +000000000000fffffffffffff3f3f30606060000001515150f0f0ff8f8f8fcfcfc060606 +000000f2f2f2fffffff9f9f9ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0ebe4dc +f5f1e8edefe1e7ead9f3f1e2f9f2eaf3e3edeadef4b3b6d994a7d19ac3ef9fd2fd8dbee6 +789fc67288ad8490c06e78bf5b64b35e62ab6c6dae7574adb5b3e4c3c0ebbfbfe5c7caed +c5caeac1c7e7b0b7d49ca1be767c969496afa2a4bd9a9dbca6aac5aaabbf8f929b4d4d4d +f4f5edf1efe3f0eee1f1eae0f1eae0f1eae2f1eae0efebe0efecddeeecddeeeddbefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecdfe9eddceaf1dfe9efe1e7ede1ebf0e9e6ebe5eceeed979998feffff +f7f7f7878684fffffbfaf7f2f1eee5fdfbeffffff6fafff9f9fffafbfffaf1f8f0f6fbf4 +fefffbfffffb52514dfffffdf3f2f0fffdfefefefefeffffe5e6e8fefffffefffff7f7f9 +f4f4f4f6f6f6fffffffffffffffffff2f2f2fefefeedededfffffffffffff5f5f5ffffff +fafafaffffffffffff010101ffffffffffffe7e7e7fdfdfdfbfbfbffffffffffffffffff +fdfdfdf7f7f7f1f1f1fffffffffffff9f9f9f5f5f5edededf7f7f7fffffff8f8f8ffffff +fbfbfbf5f5f5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0edeae5f2f1ec +e7eddfe4ebdbf0f1e3e9e2dce0cfd7e3d4e7ded9f7828aae677fa392b0d2bad5f0bdcce3 +b1acc2b8acd0a29de07574c26e68b07b75b37a71a6a89fccada7cda9a5c6b9bcdbb0b7d4 +adb8d4aab8d3b1bdd59da8beacb4c99ea4ba9599b68f93ac7a7b8d383b44f5f5f5e2e3db +e9e7dbedebdef1eae0f1eae0f1eae2f1eae0efebe0efecddeeecddeeeddbefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeceddde7efdae9f3dbe8f1dee7eddfebf1e7e8eae5ededed98979cfaf9fffffdff +76737ad2cfd6d4d3d8cfcfd1d7d7d7c6c8c5ced3ccc9d0c8c7ccc5d8dbd4d0d2cdb9b9b7 +cac8c9534f50faf5f9fffefffffefffffffff1f3f2fefffffcfffff6f8f7ffffffffffff +fffffff3f3f3fbfbfbfffffffffffffffffffffffffbfbfbf8f8f8fffffffffffff4f4f4 +fffffffbfbfb0a0a0af2f2f2fffffff7f7f7fffffffffffffafafafdfdfdf7f7f7ffffff +fffffffdfdfdfefefefdfdfdfdfdfdffffffffffffffffffedededfefefef9f9f9ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0efece5eeede8e5e8dd +eaeee0f3f3e7e1dad4d7c8cdeadce9f8f0ffe5e7ffe8f6ffe3f5ffe3f0ffe5e8f7c9bdc9 +a999b3aaa3d78280c17b75b1817aae7b73a2aca4cda49ec28885a47475918b91abaeb8d1 +b8c2dbb2bdd3979fb4a4aac0959aae74778a5456654c4c56f7f6fbdedfdaedede3f4f2e5 +ede9ddefebdff1eae0f1eae0f1eae0efebdfefebdfeeecddeeecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecdde9eed8e9f3dbe9f0dee7eddfedf0e5e9eae4eeecf199969ffffdfffefbff4e4856 +5d5763514f5452505156555351504b56584d46483b5d5f544b4d424f4e4961605c534f4e +4e4a4bfffefffcfafdfdfbfef8f8f8fefffffefffff2f6f5fefffff5f5f5fcfcfcfbfbfb +fefefefffffffbfbfbfcfcfcfffffff5f5f5fffffffffffff7f7f7fffffff9f9f9fefefe +fdfdfdf4f4f4fffffffcfcfcfffffff9f9f9fafafafffffffdfdfdfffffff2f2f2ffffff +fcfcfcfffffffffffffafafafffffff1f1f1fffffffffffffefefeffffffffffffffffff +f5f5f5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0e9dfeeeadfece8ddebe9dd +f7f3eabeb9b3eee6e4ebe5e9fffdfffbfbffeff5fff7ffffe8eefae3e7f3dcdce89897a9 +c4c9e78187ab8589af8789af8282a8a0a0c4a3a2c49897b67c7e97e0e2f76e708587889c +9d9eb3b0aec684819c555267636166dcdbd7fffffae7e4ddece9e0f2f0e4e8e4d8f0ece0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdd +ebecdaedf0ddeceee3eaece1eef1e0e9eae2eeebf69995a4fffdfffffdfffff8fffffaff +fffdf8fcf3e4fffdedfffeedf8f3e0ffffedffffeffffdecfffdf0fffff4fffff6fbf8f1 +f9f8f4fffffdf7f6f4fffffffefffff7f8fafefffffcfdffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc8 +0030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff2eadff3ebe0f4eee2f1eae0ede9e0 +b2ada7e8e5e0f7f6f4efedeefffefffdfeffeff2f9dddfebe4e8f3d8dce8858b9bced6eb +9097b17b829f8d92b27f83a6a6a9ccbdbedd9595b1696a7fe4e3f5f8f6ffe9e7f4868291 +4a45595a526aeae3f3dcd7d4f6f2e6eae6dae0dcd0f8f4e8f8f4e8e7e3d7f2eee2efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddedecda +eeefdfedede5ebebe3eef1dee9ebe0eeeaf89994a8fffbfffcf7fdfff5fff1e4f5bcafa9 +b4a794a3947f8f836dc8c2ac8d8874a6a18e736e5b999685fdfaebf9f7ebfffff6fffffa +efeeeafffffdffffffe9eaecfefffffefffffdfeffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d3 +2064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff5ede0f3ebdef3ede1f2ebe1ede9e0b7b2ac +dfdcd7ecebe9f9f7f8efeef3e8e9eeebeef5e1e3efdde1ecd8dce8adb3c3cbd1ebbec3e3 +8286a99193b98b8db39898bca2a3c29292aa676678f7f5ffebeaf0e3e1e4e5e0e6ede8ef +f7effaece5ecfffaf4f6f2e6e9e5d9ede9ddf9f5e9efebdfe8e4d8f5f1e5efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddedecdaf0eedf +edede3ebebe1eef1dee9ebe0edebf89895a8fffdfffffdfffffaff8b8293827974857c6b +7e7361a79f8c847d6bb7b1a1aaa796bcb9aa908c807c786df7f4ebfffef7fffffafdfcf8 +fffffdfafafafefffffefffffefffff2f3f5ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f7 +1851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddf5efdff1eadaede7d9efe9ddf7f3e8d3cfc6dad7d2 +cac6c3e3e1e2dcdcdee7e6ecf3f3fbe0e0eac9cbd7c8cad7c2c5d89599b6c6c9ec9294ba +74739b7c7ba3b2b0d5a5a4c3807e945a5865e9e7ece8e7e3ebe8e1f1eee7e5e0dcfffefb +e5e0dce2ded3eeeadef9f5e9f5f1e5eae6daece8dcf2eee2f1ede1efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddedecdaf0eedfefece3 +ebebe1eef1dee9ebe0edebf89895a8fffefff7f6fefffbff726a7fd1ccc9686254ede6d6 +716b5bfbf5e9726e62fffff36f6b60fffdf467645bfffff8fefbf6f1f0ecfffffdf5f5f5 +fffffffeffffeaebedfcfdfffeffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefecddefe9d9f2ecdcf0eadaece6d8f8f4e8ede9dee3e0d9c2bebb +eae8e9e6e6e8e0dfe5d0d0d8d2d2dce3e5f1dbddeac4c5d9b6b7d68080a68382aaa2a0c8 +9c9ac1aeaacd827f9a524f60e0dde4eeeae7f7f5e9edead9fcf9e6f5efdfe3ddcff0eadc +f1ede1f3efe3f6f2e6ece8dce4e0d4f3efe3faf6eae8e4d8efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddeeebdaf0eedfefece3ebebe1 +eef1dee9ebe0ecebf99795aae9e9f1fefefff6f2ff858198cccacbf5f5e9f2f0e4f9f7eb +fffff6e0ddd6fffff8f6f3ecfffffa6f6c67fffffafefdf9fffffbf0efedffffffffffff +f6f6f6fdfdfdfefffffeffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddeae4d4f5f0ddf8f2e2ede7d7eeebdcf2eee3f0ede6dfdcd7a4a3a1 +bebcbddfdde2dad9dfd2d0dbd0d0dcc5c4d2c7c6d8bcb9d6c0bcdfbbb7daa8a4c7a29cbe +595472514e63efecf7f2eeeff6f3eaeae7d4e4e2cbefebd2f0ecd3f5f0daf2eddaf6f3e4 +eeeadef0ece0f3efe3eeeadeefebdff1ede1ece8dcefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefecddeeebdaf1eedff0ece3edeae1eff0de +e8ebe0eaecf99596aafcfffffcfefffcfcff7a7a94b5b6bae8ebe4fffffaf3f4eeecebe7 +fffefbfffefbfffefbede9e87d7c7afdfcfafffffdf9f8f6fffffdfafafaf3f3f3000000 +131313f2f3f5f2f3f5ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddefead7f2edd9f7f2dff2ecdcebe8d9ede9ddeeebe2f5f2edf6f2f1b0aeaf +7c7a7f6b6a708d8b96aaa8b39a98a59c99aaa3a0b56a667f736f8a524e6946405a7a758b +dfdbeae8e3e9ece9e4fbf8e9e2ddc7ffffe6faf4dad6d0b6faf4dcf9f4e0e6e3d4e9e5d9 +f1ede1f8f4e8f4f0e4eae6daeae6daf2eee2efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefecddf0eadaf1eedff0ece3edeae1eff0dee8ebe0 +eaecf99497aafbffffecf2fef9fdff686c87c6cad3f8fefc6e74727074737f7f7fb8b6b7 +fefcfdfdfbfcfffeff7b797afaf8f9fafafaffffffdfdfdfffffff060606ffffffeeeeee +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecddf8f3e0ebe6d2eee9d6f7f2dff1eedfebe7dbe3e0d7f3f0e9eae6e3f2eeede0dee1 +918f9464616a61606853505b5b58634f4c575b57657773829f98aaf0e9fbdbd5e3fbf6fd +f2eeedf3efe6ece9d8f2eed5efebd0e4dec4fffbe3f1ebd5ece7d4f2efe0f5f1e5ece8dc +e4e0d4ede9ddf3efe3efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddf0eadaf3eddff0ece3edeae1eff0dee8ebe0eaecf9 +9497aaf6fdfff8fffff8fdff737896c4cdd6eef7f6e5edeffbffffeff0f4fffffffcfaff +f8f8fafffeff6b6b6dfffffffffffffffffffffffffbfbfb020202fdfdfdf9f9f9ffffff +f6f6f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9 +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfede9ddf0ece0f6f2e6e4e0d4 +ece8dcfbf7ebe4e0d4fcf8ecf0ece0fbf7ebdfdbcff4f0e4ece8dcfaf6eaebe7dbf0edde +ece7d4f7f2dee8e5d2ece9d6f3f0e1f3efe3e7e3d8f5f0eaf1eee9e5e1defbf7f8e2dde1 +e8e3e9f5f2f9e7e1ebede8eeefebeae4e0dfefebecfbf4fbf0e9f0e1dbdff3edeff2ede9 +efe9ddfbf6e3f0ebd5e7e2ccf8f3ddf1ecd9f0eadaf2ecdef6f2e6e3dfd3f9f5e9ece8dc +f4f0e4eae6daf4f0e4f5f1e5e1ddd1f8f4e8f0ece0f3efe3f3efe3f0ece0f1ede1ebe7db +eeeadef1ede1e4e0d4eeeadef7f3e7eae6dafbf7ebe6e2d6efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefecddf0eadaf3eddff0ece3edeae1eff1dce8ecdeeaecf89497aa +f5fcfff8ffffeff4ff6e7592c3cdd7e3edee808a8c767e8072757a808185bfbec4feffff +fdfcff6a696ef7f6fbfffffffffffffffffff7f7f7040404000000030303fffffdf1f1ef +000000000000101010f5f5f5f2f2f2ffffff030303000000020202fffffffafafaf6f6f6 +fffffffefefef6f6f6ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfe7e3d7e4e0d4f2eee2fdf9edf7f3e7 +e7e3d7dedacee8e4d8e5e1d5f5f1e5fbf7ebf1ede1e9e5d9f7f3e7e9e5d9eae7d8faf4e4 +f1ecd9f0eddaf4f1e0efecdde6e2d6e7e3d8ece8dfece9e2f1eee9d5d1cef9f5f4f7f3f4 +e9e4e8e4dfe5f8f4f3f1efe3fefcefe6e2d9f1ece8e1dcd9fbf6f3e7e2deeae6dde6e0d2 +fcf7e4e0dbc7ffffecebe5d5fbf5e7eae3d9eee7dfebe7dcf8f4e8ece8dce9e5d9e7e3d7 +ece8dcf6f2e6e3dfd3fcf8ece2ded2ebe7dbe8e4d8f2eee2e9e5d9eae6dafbf7ebf1ede1 +ede9ddf8f4e8e3dfd3f5f1e5eeeadee5e1d5f0ece0efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1e9dcf3ede1f2ebe5edeae1eff1dce8ecdeeaecf89298a8f9ffff +f4fcfff7feff7c83a0b9c3cde4eff1e9f3f5eaf2f5fcffffe7e8edf7f8fdecedf1fdfeff +727377fffefff1f1f3eeeef0fffffffafafa121212fefefeeaeaeafffffd0a0a08ffffff +ffffffe8e8e8080808ffffff000000fbfbfbfffffff0f0f0000000fffffff7f7f7ffffff +f8f8f8fffffff9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddffffdf1ede9dddedaceece8dce9e5d9f2eee2 +fffff3eeeadefaf6eae4e0d4f2eee2eae6daeeeadef2eee2efebdff6f2e6e5e2d3ece9d8 +f1eeddeae7d8edeadbf2eee2f7f3e8f1ede4e8e4dbf9f4eef8f3effcf7f3dbd6d3ede8e5 +fffdfde3ded8f0eddcedebd6f0eddef1ede2fffff6f4efe9e2ddd7f1ede2e8e5d6f8f5e4 +f3f0ddedead9e0dcd0ece8dff9f4f0e6e1ddeeeadfe5e1d5fcf8ecf6f2e6f4f0e4f8f4e8 +e8e4d8f9f5e9f6f2e6e9e5d9faf6eaf1ede1f1ede1f7f3e7f0ece0e5e1d5eeeadeece8dc +eeeadefcf8ecdedacef8f4e8e7e3d7f0ece0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff1e9dcf3ede1f2ebe5edeae1eff1dce8ecdeeaedf69298a8f9ffffeff8ff +f8fdff717693b8c0cbf8ffff7d8588777f82707477818588cdd1d4f4f8fbfcffff767a7b +f9fafcfefffffefffffefffff5f5f5000000f9f9f9fffffff6f5f3010000f8f8f8ffffff +ffffff000000eeeeee101010e7e7e7ffffffffffff0b0b0bffffffefefeff3f3f3fdfdfd +edededffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfebe7dbf6f2e6f0ece0fbf7ebeeeadee4e0d4ccc8bc +0d0900eae6daefebdff0ece0ebe7dbede9dd090500e6e2d6f0ece0f7f3e7f0ece0efebdf +f5f1e5ede9ddede9deebe7dcebe7dcf0ece3040000040000070300040000e4dfd9f2ede9 +f4f0e5e7e5d0f9f7e0edead9e6e2d6d6d2c9f6f2e9efebe2f5f1e6fffff0e5e4d2e2dfce +fefcedf5f1e6efece5e3dedbfffefbf6f2e9ece8dce4e0d4ebe7dbeeeadedfdbcffefaee +f0ece0e4e0d4f2eee2f1ede1f5f1e5f2eee2dbd7cbf3efe3faf6eae0dcd0fffdf1e9e5d9 +dad6cafffff3e9e5d9ebe7dbf4f0e4efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff0eadcf3ece2f0ebe7edeae1eff1dce8ecddeaedf69497a6f9ffffe8f1f8f8fcff +787c97b6bdc7e0e8eaeef3f6f0f5f8f5fafdebeff0f7fbfcfcfffffcffff6f7372f1f2f4 +f5f7f6f2f4f3eef0effefefe0e0e0ef6f6f6fffffff9f8f6010000fffffff0f0f0ffffff +000000ffffff000000ffffffffffffefefef040404fffffffffffffffffff6f6f6ffffff +fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdffaf6eaeae6daede9ddede9ddfffef2fcf8ec040000 +ede9ddf1ede1f6f2e6e8e4d8efebdf080400fefaeeece8dce5e1d6f6f2e7efebe0e6e2d7 +eae6dbfaf6ebf3efe4ebe7dc120b01f3ece2efe8dee4ddd3f7f0e60d0600e6dfd5e2ded2 +efecd9f1f0dbf3f1e2fffff4edeae3f2efe8f8f5eee4e1d8f5f3e6d3d4c2ffffeeeeefdd +ebe9dcefefe5eeebe6d8d5d0eae6dbf4f0e4f8f4e8e5e1d5fdf9edfffcf0dbd7cbe3dfd3 +ebe7db171307e7e3d7f7f3e7dfdbcffffbeff2eee2dfdbcff2eee2efebdfeeeadef4f0e4 +eae6dae3dfd3f9f5e9e9e5d9efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f0eadef3ece2f0ebe7edeae1eff1dce8ecddeaedf49498a4f5fafdf3fafffbfdff7d7f98 +d3d7e0f5fbfb75797abfc3c4f3f9f7fbfffff6fcfafafffefbffff676d69fcfffffcfffd +fefffdf0f2efffffff000000fffefffffefffffeff050304fdfdfdfffffff9f9f9090909 +ffffff010101fcfcfcecececffffff000000fcfcfcfbfbfbfcfcfcf8f8f8fffffff2f2f2 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc8 +0030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdff1ede1ebe7dbf3efe3ebe7dbf1ede1f5f1e5040000040000 +efebdfeae6daf9f5e9040000110d01c9c5b9f5f1e6fdf9f0e5e1d8fcf7f1f4f0e7f6f2e9 +e0dcd3f7f3e8ede9de060000e5dfd3fef8ecf4eee0fcf6e8ede7d9f5efe1fbf5e7f1eedd +f1efe0d1cfc3fffdf6f0ede8e6e2dffaf7f2e7e4dbe9eadcfeffedf6f8e3dfe1cceff0e0 +eaeadeeeeee6f7f7efeae8dce6e2d6fdf9ede1ddd1e9e5d9eae6dafcf8ecf2eee2e9e5d9 +0b0700e7e3d7fbf7ebf3efe3e5e1d5fffff3ede9ddf1ede1e9e5d9f2eee2f5f1e5e9e5d9 +eeeadefcf8ecf5f1e5efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0eade +f3ece2f0ebe7edeae1eff1dce9ecdbecedf29597a3f7fbfcfbfffff1f3ff73738baeb1b8 +fafcfbf9fbfaeaecebf4faf6bdc7bfbdc3bf5c635c6d736ffbfffdeef3effcfffde8eae7 +fefffde7e7e7080808fffefff9f7f8fffefffffeff070707030303000000f7f7f7ffffff +efefef0b0b0b0e0e0e000000fffffffffffff5f5f5ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d3 +2064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddff4f0e4ebe7dbeeeadef3efe3ebe7dbe9e5d9f1ede1070300080400f8f4e8 +eeeadee8e4d80e0a00040000f7f3e7fefaef040000fffef8ded9d5040000e8e3ddfffff6 +e4ddd3f3ece20d0700f0eadef5efe1efe9d9e3dcccf0e9d9f3ecdce7e1d3060200030000 +1c1914dad6d3ecebe90f0e0c010000101008e9eadc030400000400f5f9e2eef1dc080b00 +000200010100030100eeeadeece8dc130f03e4e0d4ebe7dbf2eee2070300eae6da050100 +060200e2ded2f0ece00804000400000a0600efebdfe9e5d9040000040000f5f1e5f5f1e5 +e8e4d8e8e4d8efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0e9dff3ece4 +f0ebe8edeae3eff1dce9ecdbecedf29597a3f6faf9eff3f6fcfdff737187d5d6dbd1d1cf +afafad858784606760768077626c64f8fff9f7fef7fbfffbf4f9f3fcfffbfefffdf1f3f0 +fffffffffffffcfafbfffefffffefff8f6f7fafafaf9f9f9fffffffffffff6f6f6ffffff +fffffff0f0f0ffffffeeeeeef4f4f4fffffff8f8f8fffffffffffffafafaffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f7 +1851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddff4f0e4eae6daf1ede1efebdfeeeadef3efe3f3efe3040000e8e4d8080400ebe7db +0d0900e8e4d8040000f7f3e7e5e1d6070200e7e2dcf6f1ed070200efeae4e3dfd6f1ede4 +efebe0080100ede9ddf6f0e2efe9dbefe9d9fef8e8ece6d6090300f7f3eae2dfd8efece7 +070300e7e6e4010000faf9f5e2e2da0b0c00dedfcdf8fae5060900dedfcd020500f5f6e8 +eceddff0eee2040000e7e3d8070300f7f3e8efebdfefebe0040000f2eee3080400e9e5da +f5f1e5040000ede9ddfaf6ebebe7db050100ece8dc0a0600eeeadee6e2d6f4f0e4e5e1d5 +f5f1e5efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeadef1ede2efece7 +edeae3eff0e0eaeadeedecf297979ffcfffdfbffffeff3fefcfeff6567665e615a777672 +f6f7f1f2faeff9fff8f8fff9f5fcf4fbfffdecf1edfcfffff5f9f8f3f7f6fcfffff6f8f7 +f4f6f5fffffffffefff5f1f2fffefff8f6f7fffffff4f4f4fefefeffffffffffffececec +fffffffefefefffffffffffff7f7f7fcfcfcfffffff1f1f1ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +ebe7dbeeeadef9f5e9e5e1d5ebe7dbf9f5e9ebe7db050100ede9dd040000f8f4e8040000 +ede9dd070300f0ece0ebe7dc030000fcf9f0e8e5de030000fffdf4e2dfd6f0ede4e7e4db +040000e5e3d7f8f4e9ece8ddfcf8edeae6dbe5e1d6090500ece9e0f1eee5e3e0d90e0b04 +edeae3030000faf7f0dfdcd3030100f7f5e9f5f3e6010200eceade030300f2f0e4e7e5d9 +f2efe6030100efece3030100f1eee5efede1edeae1030100f3f0e7030100e9e6ddebe9dd +030000030100030000080600040000fbf7eb040000e7e3d7fcf8ecf2eee2dcd8ccf5f1e5 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddedecd8eeefddefede1eee9e3 +f2ede9ece8e7eeecf197989cf9fffdf5fff7f2fff6f8fffaf3fef0fcfff6fffff8fefff6 +f9fff3eefbeaedf7ecfbfffbfdfefff7f8fdfcfffffbfffffbfffff9fffff4fdf8f9fffb +fffffdfffefffffcfffff6fbfffeffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffff3f3f3fffffffffffff0f0f0fffffff5f5f5ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddff6f2e6 +e3dfd3e7e3d7faf6eaf3efe3e9e5d9ebe7db040000f5f1e5e9e5d9040000f1ede1fdf9ed +090500e9e5d9f0ece0151209f9f6edd5d2c917140be5e2d9f5f2e9e5e2d9f2efe6090600 +f8f5ece1ded5ebe8dfece9e0e8e5dcfffff6030000ece9e0fefbf2f5f2e9030000ebe8df +110e05e2dfd6fffff60f0c03f7f4ebd9d6cd0e0b02e3e0d70b0800d4d1c8fffdf4e5e2d9 +080500f0ede4030000f1eee5f3f0e7f1eee5080500e5e2d9030000f7f4ebeae7de050200 +f8f5ecf7f4ebe4e2d6ebe7dce7e3d70a0600f8f4e8eae6daede9ddfffff3ebe7dbefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeecddebedd7eef0dbf0ece0eee9e3f4ebee +ede7ebededef959998e5f0e8f4fff6f2fff3f2fff1eafce6f2ffebfafff1fbfff3eaf9e2 +f5fff1f8fff6fbfffbf5f6fafefefffefefff2f5feeff7faf9fffff9fffdfbfffbf7f9f6 +fcf8f9fffbfffffbfffffeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffefefefffffffffffffbfbfbffffffe1e1e1fffffffafafaffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddff0ece0f1ede1 +efebdff7f3e7e2ded2eae6dafffdf10a0600dfdbcff2eee2141004ebe7dbe9e5d9040000 +f8f4e8f2eee2e3e0d70300000f0c03e6e3daf3f0e7e0ddd4fefbf2f0ede4030000dad7ce +f5f2e9f4f1e8e4e1d8120f06ece9e0030000ebe8dfdbd8cff8f5ec030000fffcf3030000 +f5f2e9e4e1d8030000f4f1e8f5f2e9030000f3f0e70f0c03f4f1e8e7e4dbfffdf4030000 +f7f4eb030000e4e1d8f9f6ed0300000e0b02ece9e0040100ebe8dff8f5ec030000f0ede4 +e9e6ddeeece0070300eeeade0a0600e1ddd1f3efe3f1ede1e2ded2f3efe3efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefecddedecd8f0efdbf0ece0f0e9e3f2eceeece7eb +ecedef929b96f5fffa445b47728f733a57398ca5887c9075899881778971768f71496245 +6f806e7682787e828384858af2f2fafefefffcfffff7fdfbeff5f1f5fcf5fefffdfffeff +fffbfffff6fbfffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffff8f8f8fcfcfcfffffff9f9f9fffffff1f1f1ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddff4f0e4eeeadee8e4d8 +eeeadef2eee2f9f5e9dbd7cb040000f9f5e9e5e1d5f0ece0ddd9cdfbf7eb040000e8e4d8 +f1ede1f4f2e6030000f5f2e9eeebe2f3f0e7f4f1e8e4e1d8edeae1f6f3ea030000151209 +0f0c03030000e2dfd6ebe8dff2efe60b0800060300090600fffcf3dfdcd3030000ece9e0 +f2efe6100d04e3e0d7ebe8df151209e0ddd40300000c0900030000030000edeae1edeae1 +f9f6ed030000030000fcf9f0030000edeae1e7e4db0e0b02e2dfd6eae7de090600080500 +030100f1ede1ede9dd050100f8f4e8f1ede1f0ece0fbf7ebe2ded2efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddeeebd8f1eeddf2ebe1f0e8e5f2eceeeae8ebeaeeed +909d94f0fff576947a3d603f6084603c5e39769671e4ffde819c7b375934799b7a445c44 +f5fff8f4faf6929397000005fffefff4f5f7f6faf9f8fdf9fcfffbfcfefbfbf9faf7f1f5 +fffdfffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffff2f2f2fffffffffffffafafafdfdfdefefeff8f8f8fafafaffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9 +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfebe7dbe9e5d9fbf7ebf1ede1 +e6e2d6e9e5d9fffef2f7f3e7eae6dafaf6eaf4f0e4efebdfe1ddd1fffff3e6e2d6f8f4e8 +f4f2e6050300f2f0e4efede1eeece0eae8dcf7f5e9eceadee7e5d9f2f0e4dcdacee3e1d5 +fcfaeef0eee2eae8dcf4f2e6e8e6daeae8dcd1cfc3eceadefefcf0f2f0e4eae8dceeece0 +efede1e7e5d9eeece0e7e5d9f9f7eb090700efede1eae8dceeece0f5f3e7e5e3d7dddbcf +fffff4ebe9ddf3f1e5e5e3d7f8f6eaeeece0edebdfeae8dcf3f1e5f9f7ebd2d0c4fffff4 +e5e1d5f4f0e4e3dfd3f4f0e4dfdbcfe5e1d5f4f0e4fbf7ebefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefecddeeebdaf3edddf2ebe1f0e8e5f2eceeeae8e9e9efeb8d9f93 +eefff4315635e3ffe74d7c4e629061426d3f648b5f3b62366e9c6e345e366b8a6bf2fff4 +e6f0e88c8e8dfffdff030004fcfafdfffffffefffdf7f9f4fbfdfafffffffcfafdfffeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffafafaf9f9f9fffffffffffffffffffcfcfcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfeeeadee6e2d6f4f0e4e8e4d8f7f3e7 +f7f3e7dbd7cbe9e5d9f4f0e4e2ded2f4f0e4f5f1e5f0ece0e4e0d4f9f5e9040000030100 +e8e6daeae8dcf3f1e5eae8dce9e7dbebe9ddf0eee2f2f0e4eceadefdfbeff8f6eaedebdf +ebe9ddf5f3e7f0eee2edebdffefcf0fffff3edebdfdcdacee7e5d9f9f7ebe3e1d5eeece0 +f3f1e5e6e4d8eceadeebe9dd030100e4e2d6f6f4e8e6e4d8f8f6eaefede1f3f1e5dad8cc +efede1e2e0d4fffdf1e9e7dbe5e3d7edebdffefcf0dcdaceefede1e4e2d6e9e7dbf9f5e9 +eae6daf2eee2eeeadefbf7ebfefaeeebe7dbe5e1d5efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddf0eadaf3eddff3eae3f1e7e5f2eceee9e9e9e7f0eb8ba091e4ffea +e4ffec245828dcffde356c355d925a33632f679964285e2a5b8c5de9ffecf0fff0f8fffa +0507040300020b0509030000dbdad8fffffbfefffbfcfefbfefffffbfcfff6f7fbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +f3f3f3f1f1f1fffffff7f7f7f5f5f5fdfdfdffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfe8e4d8f4f0e4fcf8ece5e1d5e5e1d5f8f4e8 +f2eee2f8f4e8ece8dcf5f1e5eeeadedfdbcffffdf1f1ede1e8e4d8f7f3e7f0eee2f4f2e6 +ebe9ddf3f1e5e5e3d7f2f0e4fffff4e0ded2eeece0eae8dce0ded2eae8dcf0eee2e7e5d9 +eceadeedebdfedebdfdbd9cdeae8dceeece0fffff3edebdfe8e6daf6f4e8f1efe3e4e2d6 +fffff3faf8ece8e6dafdfbefe9e7dbf0eee2f5f3e7e6e4d8e9e7dbf2f0e4f8f6eaf3f1e5 +e5e3d7eceadeedebdffffff4dddbcfefede1ebe9ddf2f0e4f6f4e8e8e6dae7e3d7fbf7eb +dfdbcff5f1e5e6e2d6e4e0d4e8e4d8f9f5e9efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddf0eadaf4ecdff4e9e3f1e7e5f2ecece9e9e7e6f1e98aa18fe9ffefcfffd7 +ddffe32d6a2fd8ffd9316f3066a0652c662b75b277caffd0e6ffeaebffeceefaeefffffb +fffdffc9c0c5140b0efffefdfffffbf2f4eff5f7f4fcfffffcfffffcfffffeffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0f0f0ffffff +fffffffffffff3f3f3151515fefefef0f0f0ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddff3efe3eae6daeae6dafaf6eaede9dde8e4d8f2eee2 +eeeadef2eee2eae6daefebdff3efe3e9e5d9e4e0d4f6f2e6ede9ddf0eee2eae8dcf0eee2 +f0eee2eeece0eceadedddbcff9f7ebe7e5d9fffff3f0eee2e5e3d7f6f4e8f4f2e6eeece0 +eae8dcf3f1e5f2f0e4ebe9dde9e7dbeceadee6e4d8f7f5e9e9e7dbe9e7dbf6f4e8dddbcf +f1efe3efede1e3e1d5f9f7ebe8e6dae3e1d5faf8ecf4f2e6e6e4d8eeece0efede1f0eee2 +f0eee2f1efe3e1dfd3f7f5e9f4f2e6eeece0edebdff1efe3f0eee2fbf7ebddd9cdfffbef +e8e4d8f3efe3f9f5e9ede9ddeae6daefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecddf1e9dcf4ecdff4e9e3f1e7e5f2ecece9e9e7e6f1e989a28fe7ffefe0ffe8306b35 +63a3671c5d1dd9ffda1f5b1d64a0641d5d216faa742a572eedffeff8fff6fcfdf8fffdff +d0c5c9060000fffdfdf8f7f3fefffbfefffff1f5f6f6fbfefcfffffeffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f4f4 +fffffff6f6f6000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdd +f1e9dcf4ecdff3eae3f0e8e5f2ecece9e9e7e6f1e98aa191e1ffe94171495a9360306d32 +67a468205d21d6ffd53671375d9d6129642e6c9970ebffedf8fff6fffffbf4eef0d9ced2 +060000fbf5f5fffffbfafcf7fefffffbfffff5fafdfbfffffefffffcfcfcfffffffefefe +fefefefffffffffffffffffffffffffffffffffffff7f7f7fefefefffffff5f5f5ffffff +fffffffffffffffffffefefefffffffffffff4f4f4fffffffffffffffffffffffffbfbfb +ffffff080808f7f7f7fafafaf3f3f3fffffffafafafffffffffffffffffff5f5f5ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc8 +0030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddf0eada +f4ecdff3eae1f0e8e5f2ecece9e9e9e7f0eb8b9f93eafff36c98742359285e97622c652e +6aa16a316330e0ffdf29642c6ca57237613becffedf8fff8fefffafffdffbeb5ba060000 +fffefdfdfcf8f2f4ef000100000100010508000306fefffff8f8f8000000080808000000 +f8f8f8fffffff3f3f3000000000000020202fefefefffffff5f5f5000000080808040404 +efefefffffff000000151515000000fffffffffffffefefe0b0b0b000000000000ffffff +000000101010060606030303f8f8f8ffffffe9e9e9000000050505000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d3 +2064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddeeebd8f3eddd +f2ebe1f0e8e5f2ececeae8e9e9efed8e9e94eafff12e55367eab843d6c405d8c603f6a3d +668c632b5629e2ffe33b6c3d6b906e3d553df8fffafefffde7e2e6d9d3d70b0708f5f4f2 +fcfdf811130efefffdf5f7f6feffff000004f5f5f7080808fffffffbfbfbffffff090909 +f9f9f90c0c0cfffffffffffffdfdfd0c0c0cf4f4f4070707fffffff5f5f5f7f7f7ffffff +fffffff9f9f9f0f0f0ffffff000000ffffff000000fffffff4f4f4fffffff0f0f0000000 +fffffff1f1f1fbfbfb060606fbfbfb131313fffffffffffffcfcfc000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f7 +1851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddedecd8f1eedbf0ece0 +f0e9e3f2ececeae8ebeaeeef909d96f1fff8edfff3e2ffe7e9ffed759877e2ffe1f0ffed +7693743e673d5c865e476647758a77000400eceeedfffeffc7c2c8010002fffffff5f7f4 +040601f7f9f6fffffff6f4f7131114fefeff000000000000030303000000080808f6f6f6 +000000fdfdfdffffffffffff000000fefefe000000f9f9f9fffffffffffff0f0f0f8f8f8 +050505070707000000080808f3f3f30f0f0fe7e7e7fffffffdfdfdffffff010101ffffff +fefefefafafa030303f8f8f80000000000001010100000000b0b0bffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddebedd7eef0daf0ece0eee9e3 +f2ececece7ebecedef929b98e9f9eff2fff8e2fbe6f0fff36c826df5fff3f3feeef7fff3 +eeffec000e00f1fff1f5fff80b110df1f2f6fffeffc8c7cd000002fcfffffcfffd000200 +f5f7f4fffeffe9e3e7040002fffeff090909f2f2f2fbfbfbf1f1f1fafafaffffff020202 +fdfdfdffffffffffff000000fefefe000000f9f9f9fffffffffffff9f9f9060606ffffff +edededffffff0e0e0efafafa000000ffffffffffffeeeeeefefefe000000fdfdfdffffff +ffffff000000ffffff010101fbfbfbffffffe8e8e8ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeeddbeaeed5edf1d8efeddeeee9e3f2ecec +ece7ebeeecf195999cf9ffffe7f4ebf5fffaf5fff68b958afcfffafffffbf5f8efecffe7 +f1ffed000700000500010506fcfdfffefeffb7b7bf000104f4faf8fbfffd000500fefffd +fffefffff7fc0d0409f0eeef000000fffffffefefeffffff0d0d0df1f1f1050505ffffff +fffffffdfdfd0c0c0cf4f4f4070707fffffff5f5f5fcfcfcffffff000000f6f6f6ffffff +ffffff000000ffffff060606edededfffffff5f5f5ffffff0a0a0afffffff6f6f6ffffff +000000f3f3f3101010fcfcfce5e5e5ffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeeddbeaeed5ecf2d8edeedeeeeae1f2ececede6ed +f0ebf298979decf0f1fbfffff9fffde7ece6878785fef8fafffafffffdfdf7fff10c1e08 +eefaecfbfffb040509f9f9fffefeffcdd0d9000205f9ffffebf4effbfffb000100030000 +11060c070002fffeffffffff000000090909000000f0f0f0fffffff7f7f7000000000000 +020202fefefefffffff5f5f5000000080808000000ffffffffffff010101040404010101 +000000fbfbfbfdfdfd0909090000000b0b0bffffff000000fcfcfcfcfcfcfefefe171717 +edededf3f3f30f0f0f0d0d0d000000f8f8f8ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddefecddefecddeeeddbeeeddbeeecddecedddeceddfeceddfeceddf +eceddfeceddfeeecddeeeddbecedddebeddfeaeedfebeeddebeeddeceddbeceddbeeeddb +eeecddefecddefebdfefebdfefebdfefebdfefecddefecddefecddeeecddeeecddeeecdd +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecddeeecddeeecddeeecdd +efecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecddeaeed7edf1daedeedeedeae1f2edeaece7ebf0ebf2 +98979dfeffffe0e4e5fcfffffeffff807c7dfffcfffff3fcfffcfffcfff8000500070e06 +000200000105fffeff080810b9bcc3000104f9fffff0f9f4fbfffdfefefcfffefffef5f8 +11080dfcfafbfffffffffffffffffffffffffcfcfcfffffffcfcfcffffffffffffffffff +f7f7f7fefefefffffff5f5f5fffffffffffff2f2f2fffffffafafafefefefbfbfbffffff +fbfbfbfffffffffffff7f7f7fcfcfcfffffffffffffefefefffffffcfcfcf6f6f6ffffff +fffffffafafaf9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9 +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f2eadff2eadff1ebddf1ebdbefecd9eeedd9eceddbebeeddebede0ebede2ebede2ebede2 +ebede0ecedddeceed9eaefdbe4f1e0e3f1e2e4f1dfe5f1dbe8f0d9eaefd9eceed9efecdb +f1ebdff2e9e0f3e8e2f3e8e2f3e8e2f3e9dff3e9ddf2eaddefecddeeecdfeeecdfeeece0 +ecece0ecece0ecece2ecece2ecece2ecece2eeece0eeecdfefecddefecddefecdbefecdd +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefecddeeebdaf0efddefeddeedebdfefeee9e9e9e7ededef97989c +f0f4f7fcfffff7fbfcfcfefd878787c9c8c6cdc9c8c4c3bfbdbfbad4d6d1bdbfbcbdbfbe +cacaccccccce000002cfd0d2000002fefffff7f9f8f7f9f80e0e0e010000100e0ff3f1f2 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1eae0 +f1ebdff1ebddefecdbeeedd9eceed9eceddbecedddebede0ebece4ebece6ecece4ecece0 +ecedddeeedd9eeeddbecece0ebede2eceddfeceddbeeedd9efedd8f1ecd9f1ebdbf2eadf +f3e9e0f3e8e4f3e8e4f3e8e2f5e8e0f5e9ddf3e9ddf1ebdfeeecdfeeece0eeece0eeebe2 +ecece2ecece4ecece4ecece4ecece2eeece0eeecdfefecddefecddf1ebdbf1ebddefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddf0eadcf1eeddf0ece0ebebdfefeee9e8eae7eceeed95999afcffff +f2f6f9f7fbfcfcffff7a7c7b0f110c00010011120d0505030000000505050e0e0e000000 +0000000000000303030b0b0bedededffffffffffffe6e6e6fffffff8f8f8ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfecece0eceddf +ecedddeceddbeceddbeceddbeeeddbeeecdfefebe2efeae4efeae6f1eae4f1eae2f1eae0 +f2eaddf8e7ddffe2e0ffdfe0ffe1ddffe3dbffe4d9fce6d8f8e8d9f5e9dbf3e9ddf2e9e0 +f2e9e2f2e9e2f2e9e2f3e9e0f3e9ddf3e9ddf1ebdfefebdfefebe0efebe0efebe0eeece0 +eeebe2eeebe2eeebe2eeece0efebe0efebdfefecddefecddefecddefecddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddf0eadcf1eeddf0ece0ebebdfefeee9e8eae7eceeed95999afcfffff1f5f8 +f9fdfefcfffffefffffefffbfffffbf6f7f2fdfdfbfefefefffffffcfcfcfffffffafafa +fffffff9f9f9fbfbfbfffffff4f4f4f7f7f7fffffffffffffffffffefefeffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeaeee0e8eee0eaeedf +ebeeddecedddeeecddefecddf1ebdff2e9e2f2e9e4f3e8e6f3e8e4f3e8e4f3e8e2f3e9e0 +f9e6dfffe1dfffdfdfffe1ddffe3dbfce6d9f8e8d9f2ebd9efecdbeeecddeceddfeeece0 +efebe0f2e9e0f3e9dff5e8dff5e9ddf2eadff1ebdff1eae0efebe0efebe0efebe0efebe0 +eeece0efebe0efebdfefebdfefebdfefecddefecddefecddefecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecddf0eadcf1eeddf0ece0ebebdfefeee9e8eae7eceeed95999afcfffffcfffffcffff +f0f4f3fefffffefffbfffffbfafbf6fcfcfafffffffcfcfcf7f7f7ffffffffffffececec +fdfdfdfafafafbfbfbf3f3f3fffffffdfdfdf2f2f2fdfdfdfcfcfcffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b +001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddfe7efe0e5f0e0e7efe0eaeedf +eceddfefebdff1ebdff3e9e0f5e8e2f6e7e2f6e7e4f6e7e4f5e7e4f3e8e4f3e8e2f2e9e0 +f1ebdfefecddeceddbeaefdbe5f1dbe3f2dbe0f4dbe0f3dde1f2dfe3f2dfe7efe0ecece0 +f2e9e0f6e8dff9e6dff9e6dff3e9e0f2e9e0f2e9e0f1eae0f1ebdff1ebdff1ebdfefebdf +f1ebdfefebdfefebdfefebdfefebdfefebdfeeecdfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdd +f0eadcf1eeddf0ece0ebebdfefeee9e8eae7eceeed95999aeef2f5fafefffbfffffcffff +fefffff7f9f4f8f9f4fffffbfffffdf7f7f7fffffffffffff3f3f3fffffff1f1f1fefefe +ffffffffffffffffffffffffe8e8e8ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff +8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc8 +0030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeceddfe7efe0e5f0e2e8eee2eaede2eeebe2 +f1eae2f3e9e0f5e8e0f6e7e0f6e7e0f6e7e2f5e8e2f2e9e4f1eae4efeae4eeebe2eaeedd +e7f1d9e5f1dbe3f2dbe0f3dddef4ddddf5dfdef4dfe0f3dfe3f2dfe8eee0ecece0f1eae0 +f5e8e0f8e7e0f8e7e0f3e8e2f2e9e2f2e9e2f2e9e0f1eae0f1ebdff1ebdff1ebddf1ebdd +f1ebddf1ebdfefebdfefebdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddf0eadc +f1eeddf0ece0ebebdfefeee9e8eae7eceeed95999afcfffffcfffff5f9faf0f4f3f2f4f3 +fefffbfffffbf8f9f4fefefcfffffffffffffffffff6f6f6fafafafffffffdfdfdffffff +efefeffafafafffffffffffffffffffffffff8f8f8ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9e +e0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d3 +2064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecdfeaeee0e8eee2ebede2eeebe4efeae4f2e9e4 +f5e8e2f5e8e0f6e8dff5e8dff2eadfefebe0ecece2eaede4e8ede6e8eee2eceddbeeedd8 +eceddbecedddecece0ebede2ebede2ebede2ecece0ecece0efebdfefebe0f1eae0f2e9e2 +f2e9e4f2e9e4f1e9e6f1e9e6f1eae4f1eae2f2e9e0f2eadff2eaddf2ebdbf2ebdbf1ebdb +f1ebddefecddefebdfeeecdfeeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddf0eadcf1eedd +f0ece0ebebdfefeee9e8eae7eceeed95999af7fbfef7fbfefafefffcfffffefffffbfdf8 +f5f6f1fffffbf5f5f3fffffff8f8f8f5f5f5fffffff2f2f2fffffffcfcfcffffffffffff +fffffff4f4f4f4f4f4fffffffffffffcfcfcffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ed +edefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f7 +1851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeece0eeebe2efeae4f1e9e6f2e8e6f3e8e6f3e8e2 +f3e9e0f2eaddefecd9eceed9e8f0dbe4f1dfe1f2e2def2e6def3e2e4f2d9e7f1d8eaeedd +ebede0efeae6f1e9e7f3e7e7f5e7e6f6e7e4f5e8e2f5e8e0f2e9e0f1eae2eeebe6ecebe7 +ecebe9eeeaebeeeae9efeae7efeae6f1eae2f2e9e0f2eaddf2ebdbf2ebdbf2ebdbf1ebdd +efecddefebdfeeece0ecece2ecece2efebe0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddf0eadcf1eeddf0ece0 +ebebdfefeee9e8eae7eceeed95999afcfffffcfffffcfffffbfffefafcfbfdfffafffffb +fffffbfffffdfffffff6f6f6fffffffffffffffffffcfcfcfffffff6f6f6fffffff6f6f6 +fffffffdfdfdffffffefefefffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2 +efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1ebdff1e7def2e5dff5e7e6f9ebebf7e9e9f0e5e3f0e9e1f4f2e5 +e4e8d1ecf7d9e9fad8d8f2cfd5f4d5ddffe7d8ffeac8f2dacbf4d2dcffdfd5f1daddede0 +eaeeede9e3e7f9e8f0fbe4ecfee3e8fde4e7fce8e7f2e4e1e6e1ddececeaeef4f4e4e9ed +e5e5edefeef4f2f0f3e9e5e4f8f3efefe8defef6e9e8e1d1f2ebd9f2ebd9f1ebdbefecdd +efebdfeeece0ecece2ecece2efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddf0eadcf1eeddf0ece0ebebdf +efeee9e8eae7eceeed95999afcfffffcfffffcfffffcfffffefffffefffbfffffbfffffb +fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb +fffff8fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7da +f4e9e5e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff2eadffbeae2ffeae7fae6e7f1e1e2f2e6e8f8f0eeefefe5dee7d2eafbd9 +ddf8cdcbefbfbbe5b5aedfb2a5d9b39ad1b28dcaa88ed5a988cfa38fc8a8ccf5e5def4f2 +eaeef7e6dbe9f7e5f3fbe4eef3dce2f5e2e4f8eeedf5f3f4ebf0f3cedbe1aebbc4a1a7b5 +a6a8b5989ba4eaebefebeae8f6f1ebe9e3d7fff8e8f2ebd9f2ebd9f1ebdbf1ebdbefebdf +eeece0ecece2ecece2efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefecddf0eadcf1eeddf0ece0ebebdfefeee9 +e8eae7eceeed95999afcfffffcfffffcfffffcfffffefffffefffbfffffbfffffbfffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8 +fefffafbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5 +e8e9fbd2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff3e9dff9e5deffe6e2fae4e6f3e3e4f2e9eaf4f5f0ecf9e8dff6d9d5f9cbbdeab1 +abdf9fa4e0a09edea28ed19e81c69a75c79947ae7749b67f3e9a7557a08c6ea09dd9f7ff +eaf6ffedecfce7dfeac6bbc3aba2a5a19fa0a1a6a9a8b3b9a7b9c59eafbfafbccfa2aabf +848b9beaeef9eff0f4f4f3efd6d2c7f5efe1f2ebd9f2ebd8f1ecd9f1ebdbefebdfeeece0 +ecece2ecece2efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefecddf0eadcf1eeddf0ece0ebebdfefeee9e8eae7 +eceeed95999afcfffffcfffffcfffffcfffffefffffefffbfffffbfffffbfffffdffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffa +fbfffffcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fb +d2edff1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f3e9dff5e1d8f8e1dbf9e7e5f7edecededebdfebe1d9f3dad9ffd6a3d69d96d38d93d888 +9ce697a4f0a89febab91deaa84d8a667c8934cae7f3a8f70488c7f4a7b808daebf97a9bf +a6aec3c2c4d3bebec6c6cacdced6d9bccbd0a4b8c390aabb849cb48293af6d7b965e6a80 +969faedce3ebe8eae9efefe7f7f4e5f1ecd9f2ebd8f1ecd9f1ebdbefecddefebe0eeebe2 +eeebe2efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefecddf0eadcf1eeddf0ece0ebebdfefeee9e8eae7eceeed +95999afcfffffcfffffcfffffcfffffefffffefffbfffffbfffffbfffffdffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbffff +fcfffffffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff +1f48a2133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9 +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff2eadf +f5e4dafbeae2f7ece8ebeae6e0ede6d6f1e0c1edccabe4b173b9717cca748ade809bf093 +aafea9aeffb6a0eeb293d9a778ac868db79fa9ccc5bcd7e0c9dbf3d9e6ffd4ddfecbd2ef +a9b1c493a0a987999d7e9698728f95789aa693b7cda9cbe7b9d3f499adce7f90ac8594a9 +e4eef8e2e7eaf1f4ede7e5d8efecdbf1ecd9f2ebd9f1ebdbefecddefebe0eeebe2eeebe2 +efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefecddf0eadcf1eeddf0ece0ebebdfefeee9e8eae7eceeed95999a +fcfffffcfffffcfffffcfffffefffffefffbfffffbfffffbfffffdffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcffff +fffdfffffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2 +133abb001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebddf1e5d7 +fdf3e7f3f0e9dbe5dddcf3e9dffff1b6eec77bc2865fb26073ce6e8dea809ffc94afffa8 +b5ffb8adf9b8a8e4b1aacbacddefe1cbdadd9babbb8f9ebf8998bf8597bd647b9a8facbe +97b8c1b7dadcd3fbfbd8ffffd1fbffc4eeffb5dcfdb7d7fe95aed66980a08a9cb4e1eefe +e5eef3e8ede7efefe3efecdbf1ecd9f2ebd9f1ebdbf1ebddefebe0eeebe2eeebe2efebe0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddf0eadcf1eeddf0ece0ebebdfefeee9e8eae7eceeed95999afcffff +fcfffffcfffffcfffffefffffefffbfffffbfffffbfffffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdff +fffcfffffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb +001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddefe9d9f0eedf +e8f0e5dcf0e5d2f6e8bdf2d88bd0a358aa6857b65c67ca6080e47297f789a4fc98a8f8a3 +adf6afb9f3c0b2d5b5c9e4d586a2a390b0bf97bcd988b3d5a8d9f9c8ffffc8ffffc0fdff +c0fcfac1f9f8c0f2f9c8f5ffccf5ffc5e8ffb9daff99b6e2657fa48ba0bddeeefee7f2f8 +e2e7e3f0f2e7eeecddefecd9f1ecd9f1ebdbf1ebddefebe0eeebe2eeebe2efebe0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddf0eadcf1eeddf0ece0ebebdfefeee9e8eae7eceeed95999afcfffffcffff +fcfffffcfffffefffffefffbfffffbfffffbfffffdffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffbfffff8fefffafbfffffcfffffffdfffffcff +fffefffbffff8a9c9ee0f0ededefe2efe7daf4e9e5e8e9fbd2edff1f48a2133abb001eae +00119b001dc8002fd32064f71a51b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4 +f1eae4f5e8dff5e9dbefebdfeceddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdbf6f1dde6e5d1e2ece3 +e8fff9c3ece47db7ab47918236916649b65d4dc04962d5527bea6781e8727ddc808de0ac +adeed68bb9afd9fcfe8fb0bfa6cee7a6dffc9fe4ffa1ebffa0edffaaf4ffb3fcffbfffff +bfffffb8f4febcf1ffbeebffb1ddffb0dcff95beec6c8ab07b8eacdfe7fae8ebf2ebece7 +ebebdfecedddeceddbeeeddbefecddf1ebdff1eae0f1eae0efebe0efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff0eadcf1eedff0ece0ebebdfefeee9e8eae5eceeed95999afcfffffcfffffcffff +fcfffffefffffefffdfffffbfffffbfffffdffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffdfffff8fefffafbfffffcfffffffdfffffcfffffeff +fbffff8a9c9ee0f0ededefe1efe7daf4e9e5e8e9fdd2edff1f48a4133abb001eae00119b +001cc80433d71c60f32057bedee7fff4ebe2edf0dfeaefdbeeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeeecdfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff1ecd9f7eed1ede7cfeef2f1e2f4fe +c5edf567a4b92e7aab1c7e8b28a35335bf3642d23246d4304dd43c5cd6736fd4cc80d2f7 +6faed1d1ffff82a5cfa1cef790dcfc87e2fd95f1ff96edffaaf2ffaff3ffabf9ffadfbff +b1f7ffb0efffaee8fca7e4ff98ddff97d4ff5d7da47d86a3ede4f5f4e5eaf4ebe2efedde +e8efdde5f0dfeaeee0ecece0f2e9e2f3e9e0f3e9ddf3e9ddf1ebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f0eadef1ede1f0ece0ebebe1efefe7e8eae5eceeeb959998fcfffffcfffffcfffffcffff +fefffffefffdfffffdfffffdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffdfffffafefffbfbfffffcfffffffdfffffcfffffefffbffff +8a9c9ce0f1ebedefe1efe7daf4e9e5e8e9fdd2ecff1f48a4133abb001eae00119b001cc8 +0433d71d5ff32057bee0e6fff4ebe2eeefdfeaefdbeeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff2ebd9f8ecd2f0e8d3efefeddff2f9c6f1fa +619dc11f69c21272af1d9a6e24b4432bc4342fc92d37cb3545cc6e53c4d25fbdfb569fd4 +b1e9ff8aafe496c6f688deff7ee6ff8aeeff91e9ffa5eaffaaecffa2f3ffa1f7ffa5f2ff +a3ecfd9ee7f897e4fe8bdfff8ed6ff5d82ac7f85a5f4e3f5f9e3e6f7e9e0f0eddce7f0dd +e4f1dfe7efe2ecece4f2e9e2f5e8e0f5e9ddf3eadbf1ebddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0eade +f1ede1f0ece1ebebe1efefe7e8ebe4eceeeb959a96fcfffffcfffffcfffffcfffffeffff +fefffffffffdfffffdffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffdfffffafefffbfbfffffcfffffffcfffffcfffffffdfbffff8a9d9b +e0f1e9edefe1efe8d8f4e9e7e8e9fdd2ecff1f47a6133abb001eae00119b001cc80433d7 +1d5ff32057bee0e6fff4ebe2eeefdfeaefdbeeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff2eaddf6e9d9f3eadbebede2def3ead1fcf5609dbc +1559c41168cf11849612976c15a45419ac4422b33e2cb36733a6b93a9dd83c8fbb89c8f1 +98c4f387bae585daf981e5fd86e6fe8de1fda0e1ffa3e2ff9aeaff97edff98eaff94e6fe +8ee2fa87e0fe82deff87d4ff618ab87b85a8f2e5f7f8e3e8f5e8dff0eddae7f0dbe5f0df +e8eee2ecece4f2e9e2f5e8e0f3e9ddf2eaddf1ebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0eadef1ede1 +f0ece1ebebe1efefe7e8ebe4eceeeb959a96fcfffffcfffffcfffffcfffffefffffeffff +fffffdfffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffdfffffafefffbfbfffffcfffffffcfffffcfffffffdfbffff8a9d9be0f1e9 +edefe1efe8d8f4e9e7e8e9fdd2ecff1f47a6133abb001eae00119b001cc80433d71d5ff3 +2057bee0e6fff4ebe2eeefdfeaefdbeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddf +ebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff2eadff3e5daf4eae0e8ebe0ddf3e7d8fff9659ebc0f51c1 +1063dd0c74b30a83940c8f810d9668109d4f169c5f1b9296228aad2b84a463a9cda7d8ff +7ab1d87ed5f17ee2fa80defa8bdbfc99d9ff9adaff8fe2ff8be6ff8ae5ff85e2ff80dffd +7adcff77daff7ed0ff6593c47686aaf1e8fdf7e4e8f4e7def0eddae8f0d9e7f0ddebede0 +eeebe4f2e9e2f3e8e2f2eadff1ebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0eadef1ede1f0ece1 +ebebe1efefe7e8ebe4eceeeb959a96fcfffffcfffffcfffffcfffffefffffefffffffffd +fffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffdfffffafefffbfbfffffcfffffffcfffffcfffffffdfbffff8a9d9be0f1e9edefe1 +efe8d8f4e9e7e8e9fdd2ecff1f47a6133abb001eae00119b001cc80433d71d5ff32057be +e0e6fff4ebe2eeefdfeaefdbeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff2eaddf4e7d7f5ebdfe7e9e4ddf0eed8ffff659bbd0d4cb50856d2 +0b6bc20a78b70c81b60c899d0a8d6d088c5b0b8a6c16887e1f7f8f448fafade0ff72acd4 +74cdeb74dcf775d6f684d8fd90d3ff90d4ff85ddff7fe1ff7cdfff78deff70dcff6ddaff +6ad4ff72caff689bd07184aceee9fff4e5eaf1e7ddf1efdaeaefd8e8f0dbecece0efebe2 +f2e9e4f2e9e2efebe0eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0eadef1ede1f0ece1ebebe1 +efefe7e8ebe4eceeeb959a96fcfffffcfffffcfffffcfffffefffffefffffffffdfffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd +fffffafefffbfbfffffcfffffffcfffffcfffffffdfbffff8a9d9be0f1e9edefe1efe8d8 +f4e9e7e8e9fdd2ecff1f47a6133abb001eae00119b001cc80433d71d5ff32057bee0e6ff +f4ebe2eeefdfeaefdbeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff1ebddf6ebd9f5ebdfebebebdeedf4d4f7fb6799ba124da90048b9025dba +0166be056eca0577b5007d79007b4f007e40067e5117757d2b759ca6daff70aad868c6e8 +66d3f268d0f577d4ff82ceff82cfff76d6ff70dbff6fdaff6cd8ff66d7ff64d4ff5ecbff +68c4ff6ba2da6b82acedebfff1e5e9efe7dcf2f0dbebefd8ebeed9efebdff1eae2f2e9e4 +f1eae4eeebe2ecece0eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff0eadef1ede1f0ece1ebebe1efefe7 +e8ebe4eceeeb959a96fcfffffcfffffcfffffcfffffefffffefffffffffdfffffdffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffa +fefffbfbfffffcfffffffcfffffcfffffffdfbffff8a9d9be0f1e9edefe1efe8d8f4e9e7 +e8e9fdd2ecff1f47a6133abb001eae00119b001cc80433d71d5ff32057bee0e6fff4ebe2 +eeefdfeaefdbeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff1ebdbf6ebd7f2e9daeeedf2e1edf9d2f0f873a0bd245da40247a20052a50055ad +0058c20065b4006e7900704200731b00712a0b656d195b8f99caff70abe35dbfec55ccf4 +56cbf663cffe6dcbff6ecbff64d2ff60d4ff63d3ff62d0ff60ceff5dccff56c3ff60bbff +6da5de6780a9ebecffefe4e8ede7d9f3f1daeceed6eceed9f1ebdff2e9e2f3e8e4f1eae4 +ebece4eaede2eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff0eadef1ede1f0ece1ebebe1efefe7e8ebe4 +eceeeb959a96fcfffffcfffffcfffffcfffffefffffefffffffffdfffffdfefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffdfffffafefffb +fbfffffcfffffffcfffffcfffffffdfbffff8a9d9be0f1e9edefe1efe8d8f4e9e7e8e9fd +d2ecff1f47a6133abb001eae00119b001cc80433d71d5ff32057bee0e6fff4ebe2eeefdf +eaefdbeeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f1ebddf4e9d7eee6d9f2f0f1e6f1f7d7f0f482abbd3b6ea7104e9b07509f004ea4004eb8 +015eae026b7e006e4c006e1e00672a06546a1148898fb9ff71acee55bdf248c8f747c9fa +51cdff5ec8ff5fc9ff57cfff56cfff5ccbff5fc8ff5ec6fd5dc4ff56bdff5fb6fb72a6df +667fa7e9ecffeee5e6ede7d9f3f1daeeeed6eeedd9f2eadff5e8e2f3e8e6f1e9e6eaede4 +e8eee2ecece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff0eadef1ede1f0ece1ebebe1efefe7e8ebe4eceeeb +959a96fcfffffcfffffcfffffcfffffefffffefffffffffdfffffdfefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffdfffffafefffbfbffff +fcfffffffcfffffcfffffffdfbffff8a9d9be0f1e9edefe1efe8d8f4e9e7e8e9fdd2ecff +1f47a6133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dc +eeeddbefebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdf +f3e9ddeae2d7edede3eaf4ebdaf2e5caedf37ea8d80d3f86074592004396004aa3005095 +00526a005c4f0369420962500b48771c45955373c881b8ff4fb8f943caff43d0ff40cbff +55d0ff46bcf943c2f94cc8fe55bff963c1fe67c0fc56abeb64c0ff57a5e56998cc6d83a8 +edf0ffe1dcd9edead9f2f2daeceed8efecd9f3e9dff6e7e2f5e7e6f1e9e6e8eee4e7efe2 +ecece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeee8dcefebdfe6e2d7f6f6ecebebe3eaede6eceeeb909591 +fcfffffcfffffcfffffcfffffefffffefffffffffdfffffdfefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffdfffffafefffbfbfffffcffff +fffcfffffcfffffffdfbffff849795e9faf2e7e9dbf3ecdcfcf1efe0e1f5d2ecff1d45a4 +133abb001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddb +efebdfefeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdffaf0e4 +eee6d9f0eedfebf2e2dff1e1defafbb7d9fe6c94d10b3c7f073c88033e8e003b7f00456c +0e5c700f5f6a00415b133e8217328b4a61be91c1ff3aa1e62bb2ec28b9f235c2fa38b6f3 +46befb52cfff57cbff52b2ef56a5e764a9ec69aef1539edf75b7f16b91be647593dbdbe7 +fffefaf2f1dfe6e8d0eceed8efecdbf5e8e0f8e6e4f6e7e4f1eae4e8eee2e7efe0eceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff1ebdff1ede1e7e3d8f0f0e6e8e8e0ecefe8edefec959a96fcffff +fcfffffcfffffcfffffefffffefffffffffdfffffdfefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeffff +fefffffefffffefffffefffffefffffefffffefffdfffffafefffbfbfffffcfffffffcff +fffcfffffffdfbffff889b99eafbf3e9ebddf0e9d9f7eceae1e2f6d5efff2048a7133abb +001eae00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdf +efeae4f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdbf7f1dbede7d1 +efecd9e9eddedeeadee7f9fbe1f9ffc0ddff5679af2d549517418d18469414468d0e4484 +1248881a478b2340902839914f5cb894baff3b9ade47c5ff3bc3fd34bbf542b5f648b5f6 +3fafee43a9e75aa9eb6ca8ee7aacf386b7fa619cd65488b77793b8dce7fdfaf7feede6de +d9d8c4fbffe8ebeed9efebdff5e8e2f8e6e4f6e7e4f2e9e2eaeedfe8efddeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefe9ddf3efe3ebe7dcefefe5e8e8e0edf0e9e6e8e5919692fbfffefbfffe +fbfffefbfffefdfffefdfffefefefcfefefcfdfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffefbfffe +fbfffefbfffefbfffefbfffefbfffefdfffcfefff9fdfffafafffffbfefffffbfffffbfe +fffefcfafffe849795e3f4eceaecdef0e9d9f5eae8e4e5f9d6f0ff1e46a5133abb001eae +00119b001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4 +f1eae4f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdbf2ecd2ece6ccefecd9 +edede1e1e6e0e3edefe5f5ffdbefffd2eaff809bca425e9f3f5aa74665b74363b83959ae +324ea14d60ad515cab6368ba85a0ef3f90cf35a4dc289fd734a6e246a5e754abf04fa8ea +5daef082bcff82aef76d8dd86685c8668ec1c4e8ffd4e4fedfe1f0f5ecedfffef3e2e1cd +e9edd6ebeeddeeece0f5e7e6f9e5e6f8e6e4f2e9e0ebeedbe8f0dbecedddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfebe5d9f2eee2efebe0f0f0e6eaeae2edf0e9dddfdc909591fcfffffcfffffcffff +fcfffffefffffefffffffffdfefffdfefffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcfffffcffff +fcfffffcfffffcfffffcfffffcfffdfffffafefffbfbfffffcfffffffcfffffcfffffffd +fbffff849795daebe3eaecdef3ecdcf6ebe9e9eafed5efff1a42a1133abb001eae00119b +001bc70837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4 +f5e8dff3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff1ecd9f5f0d3f1ebd1f3eddff3f0eb +ebe9eae4e8e9e4ede8e2eeece1eff8e6f5ffcfdeff8c9bd64f5da64959a75a6ab5596aaf +4c5c974d58905e5e9e798bc978b7ec4da5d53893c854a6e25894da82b8ff8ac6ff78aef8 +6388d64a63b34c5dad6b7abfe9ffffd7ebffe7eafbfcf5fce5d8d2ede4d5f5f4dfebf0da +eaeedfecece4f5e7e7f9e5e7f9e5e4f3e9dfeceed9eaefd8eeecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eee8dcf1ede1efebe0ecece2eaeae2eef1eae1e3e0abb0ac919594919594919594919594 +939594939594949492939592939594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +919594919594919594919594919594919594919594919594919594919594919594919594 +91959491959491959491969294958f93959090959b91949b9891989a9194959492909694 +9fb2b0deefe7eceee0f3ecdcf3e8e6e9eafed4eeff1d45a4133abb001eae00119b001bc7 +0837db1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8df +f3eadbeceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefecddf4eddbf2ebd9efe9dbf0e9dfefeae4 +ebebe3eaecdeecf0e2e1e6e0e8edf1ebf1fddfe5fdd7dcffe2e8ffe7edffd4dfffd3e3ff +eefbffe3e0ff9199c86596bf4d90ba75b4e7a9ddffa6c4ff8ca3f15b7bc84a67b55b6dbf +6670c56368bc6065a9cdd7fae7edfbf6ecf5f2e2e2fcebe1f6ebd9e8ead4e9f1dce8eee2 +ecebe6f5e6e9f9e4e9f9e5e4f5e8dfeceed8ebefd6eeeddbefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff6f0e4 +efebdfece8dde7e7dde8e8e0eff2ebedefecd6dbd7ebefeeebefeeebefeeebefeeedefee +edefeeeeeeecedefecebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefeeebefee +ebefeeebefeeebf0ecedf0e9edefeaeaeff5ebeef5f2ebf2f4ebeeefeeeceaf0eec9dcda +e9faf2edefe1f1eadaeee3e1e6e7fbd3edff254dac133abb001eae00119b001bc70837db +1d5ff31e55bce2e8fff4ebe2e9eadaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadb +eceddfebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebe2efe4eaf2e8e9ede6d4ebe5cbf0ecd1f2eed5 +efecd9f2efe0f1ede4e6e4d7f2f2d6ffffe4f5f8e5e4e7e0e5e5f1e6edfddff3fed6e8f6 +c9c5de9da0bf8baecc98c6e891b7e67086c09c9ce69a95e78d94e57b83d66668bf6360b9 +6f6cc57776ba9f9ebda9a4abe8d5d7fff9f3f8e5d6f8ecd6f9fbe5dde6d1e7efe2ebece7 +f3e7ebf9e4e9f9e5e4f6e8ddeeeed6ebefd4eeeddbefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff7f1e5ebe7db +ece8ddeaeae0ebebe3ecefe8eceeebedf2eee7ebeae7ebeae7ebeae7ebeae9ebeae9ebea +eaeae8e9ebe8e7ebeae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6eceae6ecea +e6eceae7ece8e9ece5e9ebe6e6ebf1e7eaf1eee7eef0e7eaebeae8e6eceae0f3f1e8f9f1 +eaecdef3ecdcf0e5e3e6e7fbcfe9ff264ead133abb001eae00119b001bc70837db1c60f3 +1e55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f5e8dff3eadbeeecdf +ebeddfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefeae4ece2ebf6edf0f3ecdaeeeacdf5f0d2f5f1d6f1ead7 +f2ecdef6ede4ece7d4ebe9c2ebedbee8e9c1ededd1f3f0e7e7ebeae2f2f2b9c8cdc7c5d2 +d4d3e58398a97995aaaabfdcd8dfffd5cbffbcaeeca3a1e29091d47975c17470bd7471c0 +6765a6b1adce98909fab9ba5f1dfdff2e1d9f5ecddecefdcf3fae8e8eee0ebece4f2e8e6 +f6e6e6f8e6e2f5e9ddefedd8eeedd8efecddefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff2ece0e7e3d7efebe0 +f3f1e5f0f0e6e9eae2e3e4deeef0ebebede8ebede8ebede8ebede8ecede8ecede8edece8 +ecede8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8ebede8ebede8ebede8ebedea +ebede8ebede8ebede8ebede8ebede8ebede8ebede8ebede8e9eee8e9eee8e9eee8e9eee8 +e9eee8e9eee8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8ebede8ebede8 +ebede8ebede8ebede8ebede8ebede8ebede8ebede8ebede8ebede8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8e9eee8ebede8 +e9eee8ebede8e9eee8ebede8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8 +e9eee8e9eee8e9eee8e9eeeae9eeeae9eeeae9eeeae9eeeae9eeeae9eee8e9eee8e9eee8 +e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8 +e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8 +e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8 +e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8 +e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8e9eee8 +e9eee7ebeee5ebeee7ebeceeecebf0f2e9eef2e9eaedece7e8efe7e2f1ece1eee5e8e6d9 +f8f0e3f7eee7e8ebfccbe5ff2249a8133abd001eae00119b001dc8002fd32064f71a51b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f5e8dff5e9dbefebdfeceddf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebe0efeae4efebe2f1ebddefecd9f1ecd9efecdbf1ebddefebdf +f1ebdfefecddefedd8efedd6efedd8efecdbefebe0ecebe7babfc3bcc3cbf1f1f9f8fbff +f6ffffe9f7f7f7ffffe5edf0e4e6f2bbbccea3a7c2aaaed17475a37777ad8383bf6b6aa4 +b8b6e59391b89e99b9938ea4ebe8f1f2f1efe9ebe0edefe1ebeeddeceddbf1ebddf2eadd +f2eadff2eadff1ebdff1ebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeece0eeece0eeece0eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2 +eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2 +eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2 +eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2 +eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2 +eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2 +eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2eeebe2ede9e0f5f1e8f1ece6ece8df +f0ece3eeeae1ece9e0f5f2e9efece3efece3efede1edede1edede1edede1edede1edede1 +edede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1efede1edede1 +efede1edede1efede1edede1edeee0edeee0edeee0edeee0edede1efede1efede1efede1 +efece3efece3f0ece3f0ece3f0ece3f0ece3f0ece3f0ece3efece3edede3efece3edede3 +efece3edede3efece3edede3f4f1e8e8e8def4f1e8e3e3d9e8e5dcf7f7edece9e0efefe5 +eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2eeebe2ecece2 +eeebe2ecece2eeebe2ecece2ecece0ecece0ecece0ecece0ecece0ecece0ecece2ecece2 +ecece2e4e4daefefe7ebebe3edede5dbdbd3fcfcf4ecece4edede3edede1edede1edede1 +edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1 +edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1 +edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1 +edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1 +edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1edede1eceee1 +e9eddfeaeee0f3efe6f0e7e2e8dcdeeee6e4f1f3e5ebf2e0e6eee1f6f9eee9e1d6f6eee1 +f1efe0e0eaf3d9f3ff2144a81439bd001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeebe6bebec6dcdeeae6e9f0fafefff4f9f5 +fcfffaebf3e8e7efe4ecf3ecd1d7d79ba2acc6cbdf898cad7a7ca57f81b26c6ea1a3a3d7 +b0b1e1a09fc7a8a9c7e4e5f7f5f6fbd7d8d2eef0e2eeedd9eeedd8efedd8efecd9f1ebdd +f1eae0f2e9e2f1eae2f1eae0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff3eae1f4ebe2f1e8dff1e8dff5ede2 +f2eadfeee8dcf3ede1eee8dceee8dcece9daece9daebe9daebe9daebe9daebe9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9daece9da +ece9daece9daece9daebe9daebead8ebead8ebead8ece9daece9daeee8daeee8daeee8dc +eee8dcefe7dcefe7dcefe7dcefe7dcefe7dceee8dceee8dcece8dcece8dcece8dcece8dc +ece8dcece8dcece8dcece8dce4e0d4f3efe3f1ede1f1ede1f3efe3e2ded2eae6daefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdffcfaee +edebdfeae8dcf3f1e5fbf8efeae7dee6e3dae6e4d8ebe9dcebe9daebe9dcebe9daebe9dc +ebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dc +ebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dc +ebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dc +ebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dc +ebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dcebe9daebe9dce9eadcedf4e4 +e7ebdaefe7dafcefe6fff1f4f5edebe7ead7e1e9d1d9ddceeae8dcf0e6dcf4ecdfeceddb +dce9efd8f2ff2344ab1439bd001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeebe6c4c3cbf1f0feededf7f1f2f7f0f4f5fafefd +e3e8e4f2f6f5d5daddced2db898f9fd2d6efa1a4c78788b48a8abc8686b8afaddeb1b0da +8e8daf85859ff1f0feecedf1e9eae4f0f2e4eeedd9eeedd8efedd8efecd9f1ebddf1eae0 +f2e9e2f1eae2f1eae0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff6ede4f0e7deeee5dcf3eae1f6f0e4f1ebdf +eee8dcf1ebdff4f0e4f4f0e4f4f0e4f4f0e4f3f1e2f3f1e2f3f1e2f3f1e2f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e2f3f1e2f3f1e2f3f1e2f3f1e2f4f1e2f4f1e2f4f0e4f4f0e4f6f0e4f6f0e4 +f6f0e4f6f0e4f7efe4f7efe4f7eee5f6efe5f6f0e4f4f0e4f4f0e4f4f0e4f4f0e4f4f0e4 +f4f0e4f4f0e4f4f0e4eae6daf4f0e4f6f2e6f4f0e4f1ede1ebe7dbfaf6eaefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdfdfddd1f4f2e6 +f0eee2e9e7dbe3e0d7ece9e0eeebe2f9f6edf1efe3f1efe2f1efe3f1efe2f1efe3f1efe2 +f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2 +f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2 +f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2 +f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2 +f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3f1efe2f1efe3eff0e2e4ebdbecf0df +f2eaddf4e7def9eaedf2eae8eaeddaeff7dffefff3f2f0e4f4eae0e9e1d4edeedce2eff5 +daf4ff2041a81439bd001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeebe6b8b7bfd4d3e1f0f0fce9e9f3fbfbffe1e4e9e3e6eb +e9ecf3e3e5f1dde0efa6a8bfc8cce9a6a8ce898ab68384b48e8fbda4a3cda8a8cc9797b3 +a9aabef3f3fddddfdeeaebe3edeedeeeedd9eeedd8efedd8efecd9f1ebddf1eae0f2e9e4 +f1eae2efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff6ede4ede4dbefe6ddf6ede4f3ede1f0eadef2ece0 +f3ede1ece8dcece8dcece8dcece8dcebe9dcebe9daebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dcebe9dc +ebe9dcebe9dcebe9daebe9dcebe9daece8dcece8dcece8dcece8dceee8dceee8dceee8dc +eee8dcefe7dcefe7dcefe6ddeee7ddeee8dcece8dcece8dcece8dcece8dcece8dcece8dc +ece8dcede9ddeae6daeeeadeeeeadeebe7dbebe7dbece8dcf5f1e5efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdff3f1e5f7f5e9e6e4d8 +eae8dceeebe2f1eee5f9f6ede7e4dbeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeaeadee1e8d8f4f8e7f6eee1 +eaddd4f1e2e5f8f0eeeff2dfeaf2dadbdfd0e1dfd3fff6ecf7efe2f1f2e0d6e3e9cfe9ff +2a4bb21439bd001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9 +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeebe4b4b1b8aba9b6d2d0dee5e5f1f3f2ffe0dfede7e6f4d6d7e9 +c6c7dbc8cae1c8c9e5bcbddcb0b0d69493bd7877a37f7ea6b9b8daa7a7c37d7b90e2e1ef +d8d7dcf9faf5e8e8dce8e9d9eeedd9eeedd8efecd9efecdbf1ebdff1eae0f1eae4f1eae4 +efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff5ede2ece4d9f2ece0f6f0e4ede7dbeee8dcf3efe3efebdf +efebe0efebe0eeece0eeece0eeece0eeecdfeeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeecdfeeece0eeecdfeeece0eeece0efebe0efebe0efebe0efebe0f1eae0f1eae0 +f1eae0f1eae0f2e9e0f1eae0f1ebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff6f2e6f6f2e6f5f1e5f4f0e4f3efe3f2eee2e9e5d9efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdff2f0e4eae8dce9e7dbfffff3 +fcf9f0dedbd2f3f0e7ece9e0edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1edeae1ebebdfeaf1e1edf1e0efe7daf1e4db +fcedf0fcf4f2ebeedbdce4ccf6faebf6f4e8f1e7dde9e1d4f2f3e1deebf1cfe9ff2849b0 +1439bd001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeebe4dddbdeb5b3beaaa8b3cfcddacac8d6e6e5f5e8e6fbdcdaf0e3e1f9 +ceceeac9c8e78b8cab8d8daf9b9bbfa3a3c7bbbadc9898b2807f91878694eeeff4dbdbdb +f8f9f1f4f5e7edeedceeedd9eeedd8efecd9efecdbf1ebdff1eae2f1eae4f1eae4efebe0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff2ece0ede5daf6f0e4f6f0e4e8e2d6f0eadef2eee2dedaceede9de +ede9deeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0eceadeece9e0 +eceadeece9e0eceadeeceadeeceadeede9deede9deede9deede9deefe8deefe8deefe8de +efe8def0e7deefe8deede9ddede9ddede9ddede9ddede9ddede9ddede9ddede9ddf0ece0 +efebdfe1ddd1e9e5d9f2eee2f3efe3f9f5e9efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdd +eeecddeeecddeeecddeeecddeeecddeeecdfeeecdfebe9ddefede1e7e5d9dedcd0e6e3da +f7f4ebe4e1d8f4f1e8edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1ebebe1e9efe1dee2d1ede5d8f9ece3eedfe2 +e5dddbecefdcf3fbe3cfd3c4fffff4e9dfd5e5ddd0f0f1dfe7f4fad2ecff2445ac1439bd +001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeebe2f9f8f6e0dee1b6b3bab1b0b8a9a7b4ccc9dacecbe0cccae0c5c3dbc9c9e3 +d5d5f1c0c0dcb8b8d4b4b4d0a0a0bc8f8fa7757484878590e3e2e8fffffff5f4efd9d9cf +edebdcf3f2e0eeedd9eeedd9efecdbefecddf1eae0f1eae2f1eae4f1eae4efebe0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff2ece0ede7dbf7f1e5f4eee2e5e1d5f2eee2ece8ddc1bdb2aeaca0aeaca0 +aeaba2aeaba2acaca2acaca2acaca2acaca2acaca2acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2acaca4acaca2 +acaca4acaca2aeaba2aeaba2aeaba2aeaba2afaba2afaba2afaba0afaba0b1aaa0b1aaa0 +b1aaa0b1aaa0afab9fafab9fafab9fafab9fafab9fafab9fafab9fafab9fb5b1a5a9a599 +a19d91cecabeebe7dbe6e2d6efebdfece8dcefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddeeecdd +eeecddeeecddeeecddeeecddeeecdfeeecdfe7e5d9f5f3e7f8f6eaeceadef6f3eae8e5dc +0300000b0800050200050200050200050200050200050200050200050200050200050200 +050200050200050200050200050200050200050200050200050200050200050200050200 +050200050200050200050200050200050200050200050200050200050200050200050200 +050200050200050200050200050200050200050200050200050200050200050200050200 +050200050200050200050200050200050200050200050200050200050200050200050200 +050200050200050200050200050200030300050b00000300140c00180b020a0000060000 +0c0f000005000e1203dfddd1fdf3e9fffbeee8e9d7d8e5ebcce6ff294ab11439bd001eae +00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebe0e6e3dcf5f4f0e2e0e1a7a5a8aeabb4a2a0ada19eaf9d9aaf9793aaa09eb4918fa5 +9e9fb39293a7999aac9799a881808ef7f6fee3e3e5edebece3e2dee6e6def7f7ebe8e6d7 +ebead8eeedd9eeeddbefecdbefecddf1eae0f1eae2f1e9e6f1eae4efebe0efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff2ece0ede7dbf6f0e4f2ece0e7e3d7f6f2e6e6e2d7aaa69b706e62706e62706d64 +706d646e6e646e6e646e6e646e6e666e6e666e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d686e6e666e6d68 +6e6e66706d66706d64706d66706d64716d64716d64716d64716d62736c62736c62736c62 +736c62716d61716d61716d61716d61716d61716d61716d61716d61736f636d695d827e72 +dedacefffff3f7f3e7f1ede1ece8dcefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecdd +eeecddeeecddeeecddeeecdfeeecdff4f2e6e8e6daebe9ddeceadeece9e0f2efe60a0700 +f3f0e7fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff6fbfff3f4f8e7fffef1fff8effff1f4fffdfbedf0dd +707860000300f0eee2f0e6dcefe7dadedfcdebf8fed9f3ff1c3da41439bd001eae00119b +001ec90031d42165f81952b9e3ecfff0e7def0f3e2e9eedaeeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f0ece0ede9ddefebdfeeeadeebe7dbf7f3e7e5e1d5fbf7ebf1ede1f0ece0e1ddd1f7f3e7 +f7f3e7e7e3d7f8f4e8ebe7dbf3efe3e5e1d5f9f5e9e1ddd1f0ece0f7f3e7eae6daefebdf +ebe9ddf1efe3ece9e2f1edeaf1ecf09592998986917a788577758382808e807e8b80808c +84848c86878cdbdce0f5f6f8f3f1f2deddd9fefbf6e5e2dbf4f2e6eceadddddbccf7f6e4 +edead9f4f1e0e9e6d7eae6dae7e3d8fffdf4eee6e3f4ede7f0ece1e9e5d9e5e1d5f5f1e5 +f2eee2efebdffcf8ece9e5d9efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfece8dcf5f1e5ebe7db +f4f0e4ede9ddf2eee2e8e4d8f4f0e4eae6daf1ede1f3efe3e6e2d6f4f0e4f2eee2f4f0e4 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f1ede1ece8dcf3efe3ece8dcefebe0f0ece1f0eee2aba99d7a776efaf7eefffff8fcfcf4 +fffff8fffff8ebece4fffffafcfbf6fbfaf5fffffbfffffafffffbf0efeafffefafffffa +faf9f5fffffaf9f8f4f2f1ecfbfaf6fffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffafffffbfffffa +fffffafffff8fffffafffff8fffdf6fffff6f6f2e9f9f5ecfaf6ebeae6dbf5f1e6f8f4e9 +f7f3e7f1ede1efebdffcf8ecede9ddfffdf1f4f0e4f5f1e5fffff3d0ccc07c786cf7f3e7 +fffdf1f2eee2f1ede1f3efe3efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecdd +eeecddeeecddeeecdfeeecdfedebdfeeece0eeece0edebdfeeebe2edeae1050200fffef5 +f5f2ebf3f0e9f1eee7f1eee7f2efe8f3f0e9f2efe8f1eee7f3f0e9f3f0e9f3f0e9f3f0e9 +f3f0e9f3f0e9f3f0e9f3f0e9f0ede6faf7f0f0ede6f5f2ebf7f4edf1eee7f0ede6f9f6ef +eae7e0fffef7edeae3edeae3f0ede6f4f1eaf2efe8f6f3ecf5f2ebf6f3ecf6f3ecf0ede6 +f0ede6f1eee7f5f2ebf5f2ebe6e3dcfffff8f0ede6f1eee7f6f3ecf7f4eddddad3fffef7 +f3f0e9f3f0e9f3f0e9f3f0e9f3f0e9f3f0e9f3f0e9f3f0e9f3f0e9f3f0e9f3f0e9f3f0e9 +f3f0e9f3f0e9f3f0e9f1f1e7ebf1e3f0f4e3f5ede0faede4f7e8ebf8f0eea9ac99707860 +000400eeece0f2e8def3ebdeeaebd9e4f1f7cee8ff2546ad1439bd001eae00119b001ec9 +0031d42165f81952b9e3ecfff0e7def0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeae6da +f2eee2f8f4e8e1ddd1f2eee2ebe7dbf4f0e4e3dfd3f2eee2ebe7dbfffff3d9d5c9e5e1d5 +fbf7ebdfdbcfeeeadef4f0e4f2eee2e7e3d7f5f1e5f3efe3e7e3d7fffcf0ebe7dbf0eedf +edebdceeecdff9f6edefece7ede9e8f0ebeff2f0f5e9e6edf5f4f9e7e6ebe4e4e6e4e4e4 +e1e3e0e5e7e2f0f1ebe2dfdaf4f1eaeeebe2eceadef5f3e6f4f2e5faf8e9dfddcee8e5d6 +f5f2e3e9e5d9ede9defffff6d5d1c8ece5dff4ede7f0ece1fefaeef6f2e6e9e5d9e6e2d6 +ebe7dbf3efe3f6f2e6efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfece8dcf3efe3e8e4d8faf6eaece8dc +f0ece0f5f1e5f8f4e8f2eee2e3dfd3eeeadef3efe3ebe7dbf2eee2e6e2d6e2ded2efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ede1 +ece8dcf3efe3ece8dcefebe0f0ece1f0eee2aba99d646158fffff6fffff8fdfdf5fcfcf4 +fdfcf7fffffafffffafffffbfffffbf3f2eefffffbfffffbf4f3effffffbe3e2defffffb +f0efebfffffbfffffbfffffbfffffbfaf9f5f9f8f4fffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffb +fffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffbfffffdfffffbfffffb +fffffafffffafffffafffef9faf7f0f7f2ecfffef5fcf8effffff4fffff4f7f3e8fefaee +fffff3fffff3fffff3fffdf1fdf9edfffff3fffef2f7f3e7c0bcb0726e62f3efe3fffcf0 +f2eee2f0ece0f2eee2efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecdd +eeecddeeecdfeeecdfedebdfeeece0eeece0edebdfeeebe2edeae1050200fffef5f3f0e9 +f1eee7efece5efece5f0ede6f1eee7f0ede6efece5efece5efece5efece5efece5efece5 +efece5efece5efece5e9e6dff2efe8ece9e2e9e6dff3f0e9f4f1eaebe8e1ece9e2f6f3ec +dfdcd5f7f4edfffef7f9f6efeae7e0e3e0d9f5f2ebe1ded7e9e6dfeeebe4fffff8f2efe8 +eeebe4e5e2dbf2efe8f7f4eddbd8d1edeae3ece9e2ece9e2ebe8e1fefbf4e1ded7efece5 +efece5efece5efece5efece5efece5efece5efece5efece5efece5efece5efece5efece5 +efece5efece5edede3e9efe1eef2e1f3ebdef8ebe2f5e6e9f6eeeca7aa976e765e000400 +eeece0f2e8def3ebdeeaebd9e4f1f7cee8ff2546ad1439bd001eae00119b001ec90031d4 +2165f81952b9e3ecfff0e7def0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0ece0f2eee2 +ece8dcfcf8ecf9f5e9e9e5d9f4f0e4f7f3e7dad6cafcf8ecede9ddf5f1e5fffdf1dcd8cc +faf6eaf6f2e6e5e1d5ebe7dbf4f0e4f1ede1f2eee2ede9ddeae6dae8e5d6f1eedde4e1d0 +fcf9eaede9ddeeeae1f1eee7f4f1ece7e6e1fdfcf8d3d2cef4f3eff0f1ebf5f6eefffff6 +eaece1e9ebe0f7f4ebe6e2d7eeeadff8f4e8eae6dae2ded2e4e0d4f4f0e4fdf9ede5e1d5 +f7f3e8f0ece1e3dfd6fbf7eef1ece6eeeae1e5e1d6e6e2d6e7e3d7ede9ddfdf9edf1ede1 +ddd9cdf2eee2efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfebe7dbfaf6eae3dfd3e3dfd3eae6daefebdf +eeeadeebe7dbebe7dbf8f4e8f1ede1f5f1e5e7e3d7ece8dcf1ede1fffdf1efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1eedfece9da +f3efe3ece8dceeece0efede1f0ede4aba89f797971fffff8e9e8e3fffffafffffafffffb +f8f9f4f3f4effffffdf1f1effffffdfffffdf0f0eefffffdfefefcfffffdfafaf8fffffd +f5f5f3fcfcfaf4f4f2fefefcfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffffffffdfffffdfffffb +fffffbfffffafffffaf3f0e9f3f0e9fffff6e5e1d8f0ece3ede9def3efe4ede9ddf5f1e5 +e0dcd0e5e1d5f3efe3ebe7dbf7f3e7f1ede1e9e5d9b4b0a46b675bf2eee2fffef2f2eee2 +ede9ddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecdd +eeecdfeeecdfedebdfeeece0eeece0edebdfeeebe2edeae1050200fffef5f1eee5efece3 +edeae1edeae1eeebe2eeebe2eeebe2edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1edeae1efece3edeae1efece3ebe8dff4f1e8edeae1e8e5dcf8f5ecece9e0edeae1 +e5e2d9efece3d1cec5fffcf3fcf9f0dddad1f8f5eceeebe2eeebe2d4d1c8efece3efece3 +faf7eee5e2d9e4e1d8f5f2e9f6f3eaf3f0e7edeae1eae7deebe8dffcf9f0edeae1edeae1 +edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1edeae1 +edeae1ebebe1e7eddfebefdef1e9dcf6e9e0f3e4e7f4eceaa5a8956c745c000400eeece0 +f2e8def3ebdeeaebd9e4f1f7cee8ff2546ad1439bd001eae00119b001ec90031d42165f8 +1952b9e3ecfff0e7def0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff8f4e8e4e0d4f3efe3 +e0dcd0e9e5d9f4f0e4e7e3d7f5f1e5fffff3e5e1d5e9e5d9eae6dadcd8ccf8f4e8f9f5e9 +e0dcd0f4f0e4e2ded2f7f3e7ebe7dbe4e0d4f2eee2efebdfefecdde6e3d4ffffeff3f0df +dfdccde4e0d4f1ede2eeeadfebe9ddeae7deeeeee4f2f2e6f3f3e7d4d4c8dbddd0f0f2e5 +edede1f1ede2e8e4d9f8f4e8ebe7dbe7e3d7ece8ddf7f3e8f4f0e5f1ede2dad6cbf0ece3 +ede9e0f3efe6e9e5dcf6f1ebeeeae1fffcf1eeeadeefebdfede9ddf2eee2f1ede1e4e0d4 +f3efe3efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfe4e0d4efebdffffff3e9e5d9f1ede1ece8dcfaf6ea +ebe7dbf5f1e5eeeadee5e1d5f1ede1e4e0d4f9f5e9ede9dddbd7cbefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1eedfece9daf3efe3 +ece8dceeece0efede1f0ede4aba89f6f6f67fcfcf4fffffaf7f8f2fefffaf6f7f2fffffb +fffffdfbfbf9fffffdfffffff3f3f1fffffffffffdf9f9f9f3f3f1ffffffededebfefefe +fffffdfffffffffffdf5f5f5fffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdffffff +fffffdfffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffdfffffd +fffffbfffffaf8f5f0f5f2ebfffff8e7e3daf7f3eae4e0d5f9f5eaebe7dbf5f1e5ebe7db +f4f0e4f8f4e8f8f4e8e6e2d6e7e3d7ebe7dbb5b1a56c685cf5f1e5fffff3f1ede1ece8dc +eeeadeefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdf +eeecdfedebdfeeece0eeece0edebdfeeebe2edeae1050200fffef5f0ede4eeebe2ece9e0 +ece9e0edeae1eeebe2edeae1ece9e0efece3efece3efece3efece3efece3efece3efece3 +efece3f3f0e7e7e4dbf4f1e8f4f1e8f6f3eadfdcd3e4e1d8f5f2e9ebe8dffffdf4e1ded5 +e7e4dbfffff6e1ded5ebe8dff0ede4e0ddd4ece9e0fffef5eae7def3f0e7e6e3daf3f0e7 +e8e5dceeebe2eeebe2e6e3daefece3e9e6ddf2efe6eae7deeae7deefece3efece3efece3 +efece3efece3efece3efece3efece3efece3efece3efece3efece3efece3efece3efece3 +edede1e6edddebefdef1e9dcf5e8dff2e3e6f4eceaa4a7946c745c000400eeece0f2e8de +f3ebdeeaebd9e4f1f7cee8ff2546ad1439bd001eae00119b001ec90031d42165f81952b9 +e3ecfff0e7def0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfe7e3d7f6f2e60c0800f6f2e6 +f8f4e8e6e2d6fffff3e3dfd3040000e8e4d8f7f3e7f4f0e4f7f3e7f1ede1e4e0d4f6f2e6 +f8f4e8f6f2e6dfdbcf141004fbf7ebdad6caf4f0e4e8e4d8090300e5dfd3eee8dcfffff1 +ebe5d9f9f6e7e6e3d4f9f7e8e9e7d8f9f7e8e0ded1e3e4d6fefef2f1f1e5eeeee2ebebdf +f6f2e7f3ede1f2ebe1f0e9dffffcf2e6dfd7faf3ebdfd8d0e8e4dbfffff6f9f4eee1ddd4 +f5f1e8060200d6d2c9f6f2e9e7e3d8e7e3d7f8f4e8f0ece0e1ddd1f3efe3faf6eae8e4d8 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdffcf8ecdedacee7e3d7f6f2e6e6e2d6e9e5d9eae6daefebdf +f1ede1e6e2d6f5f1e5fbf7ebe3dfd3f2eee2fffdf1efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0eedfebe9daf2f0e1ebe9dc +eeece0efede1eeeee4a9a99f7c7c74f7f7effffffafbfcf7fbfbf9fffffdeef0edf8faf9 +fffffffffffffffffff4f4f4fffffffffffff4f4f6fffffffdfdfffffffff9f9fbffffff +f5f5f7fdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffefffffefffffffffffffffffffffffffffdfffffdfffffb +f7f6f1fffffaf8f5eefefbf4ece9e0fffff6e3e1d5e8e6daeae6daede9ddeeeadef0ece0 +ddd9cdfaf6eae6e2d6fffff3f0ece0b6b2a66d695df6f2e6fffff3f1ede1ece8dcf1ede1 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdf +edebdfeeece0eeece0edebdfeeebe2edeae1050200fffef5f1efe3efede1edebdfedebdf +eeece0efede1eeece0edebdfefede1efede1efede1efede1efede1efede1efede1efede1 +f4f2e6e8e6daebe9dde3e1d5f1efe3faf8ecfffff4e8e6da030100030100110f03030100 +eeece0e2e0d4f1efe3f9f7ebeeece0e8e6dadedcd0f7f5e9eae8dceeece0e5e3d7f7f5e9 +eae8dcf3f1e5eceadee2e0d4f9f7ebefede1e8e6daf1efe3efede1efede1efede1efede1 +efede1efede1efede1efede1efede1efede1efede1efede1efede1efede1efede1edede1 +e7eedeecf0dff2eaddf6e9e0f3e4e7f5edeba5a8956d755d000400eeece0f2e8def3ebde +eaebd9e4f1f7cee8ff2546ad1439bd001eae00119b001ec90031d42165f81952b9e3ecff +f0e7def0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfebe7dbf0ece0040000e3dfd3ece8dc +fbf7ebece8dcf2eee2040000f6f2e6f5f1e5e3dfd3f7f3e7f9f5e9e6e2d6f7f3e7d6d2c6 +f8f4e8ece8dc070300040000faf6eaf6f2e6f5f1e6060000fcf5edf8f1e7e1dad0f5efe3 +f2ecdeeae7d6e4e1d0efeedc030200eeecddefede0ecece0e7e7ddf6f6eee8e5dce6dfd5 +e4ded2fff8eeddd6ccefe8e0f6efe7ebe4defef7f1f0ebe5eae5dfe1dcd6eee9e3fefaf1 +040000fffff6eeeadff5f1e5e7e3d7e2ded2f7f3e7f5f1e5ece8dcf5f1e5e3dfd3efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfe8e4d8faf6ea080400040000040000060200040000f5f1e5040000 +fffff3040000f8f4e8f7f3e7e6e2d6d2cec2f9f5e9efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff0eedfebe9daf2f0e1ebe9daeeece0 +efede1eeeee4a9a99f595951fffffaf0f1ecfffffb0e0e0c000000010302fefffffcfcfe +0000020303050a0a0c000002000002ffffff000002000002000002000002000002ffffff +fafafcfffffff9f9fbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffefffffefffffffefffffffffffffffffffffffffdfffffdfffffb +fffffaf1eee7fffff8eae7dee4e1d8e8e6dafffdf1faf6eaede9ddede9ddf6f2e6e3dfd3 +f6f2e6e5e1d5e2ded2eeeadeb3afa3696559f4f0e4fffff3f0ece0ede9ddf5f1e5efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdfedebdf +eeece0eeece0edebdfeeebe2edeae1050200fffef5f2f0e4f0eee1eeece0eeecdfefede1 +f0eee1efede1eeecdfeeece0eeecdfeeece0eeecdfeeece0eeecdfeeece0eeecdfdcdace +f0eee1fbf9edf1efe2f5f3e7eae8dbc8c6ba060400fbf9edebe9dcf4f2e6f2f0e3060400 +f2f0e3e2e0d4e3e1d4f4f2e6f2f0e3f3f1e5e7e5d8f5f3e7f4f2e5f2f0e4e0ded1eeece0 +f3f1e4e4e2d6fcfaede5e3d7fefcefefede1f3f1e4eeece0eeecdfeeece0eeecdfeeece0 +eeecdfeeece0eeecdfeeece0eeecdfeeece0eeecdfeeece0eeecdfeeece0eceddfe8efdf +edf1e0f2eaddf7eae1f4e5e8f5edeba6a9966d755d000400eeece0f2e8def3ebdeeaebd9 +e4f1f7cee8ff2546ad1439bd001eae00119b001ec90031d42165f81952b9e3ecfff0e7de +f0f3e2e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff7f3e7e9e5d9040000080400f1ede1eae6da +eeeade0804001d190ddbd7cbf5f1e5ece8dcf3efe3ddd9cdfbf7ebede9ddfefaeef6f2e6 +e7e3d70400001f1b0feae6daf3efe3e5e1d6130b08ede3e2e7dfdce8e1d9f9f2e8f8f2e4 +e6e3d2fcf9e6f9f6e3040100f2f1dffffff2d8d5ccfdfaf3dad7d2faf7f2ebe4dafffef3 +eae1d8f4ebe2f9f2eaf7f0eae8e0ddeee6e3efe7e4fffbf8ede8e2eee9e3efebe2070300 +f3efe4dfdbd0e4e0d4fffff3e6e2d6efebdff9f5e9dcd8ccefebdff4f0e4efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdffbf7ebddd9cd090500efebdff3efe3fffff3d5d1c5f0ece0f2eee2e7e3d7 +141004d5d1c5efebdff8f4e8fefaeeece8dcefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff0eedfebe9daf2f0e1ebe9daeeece0efede1 +eeeee4a9a99f787971f6f7f1fffffb000100f3f5f2fefffffdfffe010302ffffffffffff +fcfcfef6f6f8ffffff000002ffffffffffffffffffffffffffffff000002ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffefffffefffffefffffefffffffffffffffffffffdfffffdfffffbfaf9f4 +edeae3fffff8f4f1e8e4e1d8fffef2d6d4c8eae6dae6e2d6eeeadefcf8ecf5f1e5e0dcd0 +fffff3e8e4d8ece8dcb0aca0686458f6f2e6fffff3efebdfebe7dbf3efe3efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdfeeecdfedebdfeeece0 +eeece0edebdfeeebe2edeae1050200fffff3f2f0e3f0eedfeeecdfedebdcefede0efedde +efede0edebdceeecdfeeecddeeecdfeeecddeeecdfeeecddeeecdfeeecddf7f5e8fbf9ea +e9e7dae0decfe9e7daf6f4e5fffdf00c0a00e9e7daf0eedfeeecdfe0decf040200f0eedf +f8f6e9f9f7e8eceaddefeddeeae8dbeceadbe7e5d8f0eedff1efe2f5f3e4ebe9dcf2f0e1 +f4f2e5edebdceeecdfe7e5d6e9e7daf0eedfeeecdfeeecddeeecdfeeecddeeecdfeeecdd +eeecdfeeecddeeecdfeeecddeeecdfeeecddeeecdfeeecddeeecdfeceddfe8efdfecf0df +f2eaddf7eae1f4e5e8f5edeba6a9966d755d000400eeece0f2e8def3ebdeeaebd9e4f1f7 +cee8ff2546ad1439bd001eae00119b001ec90031d42165f81952b9e3ecfff0e7def0f3e2 +e9eedaeeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeeadef5f1e5040000050100fcf8ece8e4d8efebdf +040000050100e1ddd1f4f0e4040000e4e0d4fbf7eb0e0a00e8e4d8ede9dde6e2d6f4f0e4 +070300efebdf040000e2ded2fcf8ef060000fff8f6efe7e4f9f4ee060000040000090600 +ece9d8edead9050200060400e2e0d4040100f3f0ebf2eeeb040000f5eee6e7e0d6060000 +f7f0e8eee7e1040000100805040000f3ebe8e8e3df060100040000f3efe6040000ebe7de +f9f5ea0a0600dedacefaf6eae9e5d9f7f3e7e8e4d8f9f5e9eae6daefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfe6e2d6faf6ea040000ede9ddede9ddeae6daf4f0e4f0ece0f3efe4f0ece1040000 +fdf9eef7f3e8e5e1d6eae6dbece8ddefebe0efebe0efebe0efebe0efebe0efebe0efebe0 +efebe0efebe0eeece0efebe0eeece0efebe0eeece0efebe0eeece0efebe0eeece0efebe0 +eeece0efebe0eeece0efebe0efebe0efebe0efebdfefebe0efebdfefebe0efebdfefebe0 +efebdfefebe0efebdfefebe0efebdfefebe0efebdfefebe0efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff1eedfebe9daf3f0e1ebe9daeeece0efede1f0ede4 +a9a9a16b6a65fffffbfdfef9020200fffffffeffffffffff000002fffffff7f7f7ffffff +ffffff000002fffffffdfdfffafafafffffff7f7f7070709fcfcfcfffffffefefef0f0f2 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffefffffefffffefffffefffffffffffffffffffffdfffffdfdfcf8fffffaf3f0e9 +fffcf3e8e5dcf5f3e7e3e1d4110f020501000c0800040000040000040000060200e2ded2 +f6f2e6eeeadeb2aea26b675bf9f5e9fffff3efebdfe8e4d8efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeecdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdfedebdeeeece0eeece0 +edebdfeeebe2edeae1050200fffef5f1efe2efeddeedebdcedebdceeecddefeddeeeecdd +edebdcefeddeefeddeefeddeefeddeefeddeefeddeefeddeefeddeeeecddeceadbe2e0d3 +f8f6e7f1efe2e1dfd0f6f4e7030100e9e7daf0eedfeae8dbfaf8e9030100e9e7d8f4f2e5 +030100040200050300030100fffef1e4e2d5e4e2d5131104030100040200ebe9dceae8db +0a0800e8e6d9070500060400edebdeefeddeefeddeefeddeefeddeefeddeefeddeefedde +efeddeefeddeefeddeefeddeefeddeefeddeefeddeefeddeedeedee7eedcebefdef1eada +f6e9e0f3e4e7f4eceaa5a8976c745d000400eeece0f2e8dff3ebdeeaebd9e4f2f5cee8ff +2547ab1439bd001eae00119b001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dc +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfe9e5d9f6f2e6070300f5f1e5040000ede9dd040000f6f2e6 +0c0a00e2e0d4e9e7db0e0c00e2e0d4f5f3e7090700eae8dcefede1f0eee2ebe9dd080600 +ebe9dd030100fffdf1e3e0d7040000fffaf6f0ebe5030000f0ebe5e7e4dbf2efe6030100 +e6e4d8090700e8e5dcebe8df030000fffcf5dfdcd7080500e3ded8f9f5ec050100e7e2dc +040000f4f1eaece7e1f0ede60f0a04e4e1da030000ebe8e1f3f0e9030000fcf9f2030000 +e7e3d8fefaeee7e3d7f2eee2ece8dce7e3d7f1ede1f2eee2efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f2eee2ece8dc0b0700fefaeee2ded2eeeadef8f4e8e6e2d7040100eeebe2030000eeebe2 +e7e4db151209030000030000f2efe6e3e0d7f8f5ecf3f0e7e1ded5040100ece9e0080500 +0a0700deded4f0ede4edede30603000303000b0800e5e5dbece9e0070700060300010100 +eeebe2010100080500ece9e0edeae1f2f0e4030000030100070400f5f3e7e0ddd4060400 +eeebe2eeece0eeebe2eeece0eeebe2eeece0eeebe2eeece0efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff1eedfece9d8f5efe1ece9daefebe0f0ece1f1ede4aba8a1 +686560fffffbf8f7f5030102fffefff1f0f5fffeff000004f8f8f8fffffdf2f2f2fffffd +050505fcfcfafdfdfdfffffdfffffffffffd010101f1f1effffffff7f7f5fffffffdfdfb +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffdfffffffffffd +fefffdfefffdfefffffefffffffffffffffdfffffdfffffdfffefafffffaf3f0e9fffff6 +eceaddeceadbf1f0deedebdc0602000400000b0700040000050100f1ede2f3efe4f1ede2 +f0ece1aaa69b767267f1ede2fffff4eeeadfeeeadff0ece1efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeecdfeeecdfeeecdfeeecdfeeecddeeecddeeecddeeecddedebdceeecdfeeecdfedebdf +eeebe2edeae1050200fffef7f3efe4f1ede1efebdfefebdff0ece0f0ece0f0ece0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfedebdeefede0fcfaeee1dfd2 +f1efe3ebe9dcefede1030100eeece0f0eee1e6e4d8eeecdf030100edebdef0eee2030100 +ece9e0f4f1e8e4e1d8050200f2efe6151209e1ded5edeae1ebe8df030000ece9e0030000 +0b0800f1eee5eeebe2030100efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeceddde7eedcebf0dcf1eadaf6e9e0 +f3e4e7f4ebeca5a7996c745f000400eeebe2f2e8dff3ebe0eaecd7e4f2f5cee8ff2547ab +1439bd001eae00119b001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff3efe3e6e2d6040000f0ece0090500f6f2e60a0600e4e0d4050300 +fffef2e5e3d7040200f2f0e4e8e6da060400efede1f5f3e7e3e1d5eeece0080600e5e3d7 +efede1030100f9f7eb120f06eae7e0e3e0d903000005020016130c030000100d06f9f6ef +030000fffcf5f0ede6030000e4e1da131009e8e5de14110ae3e0d9030000fbf8f1030000 +e6e3dcf4f1eaece9e2030000f8f5ee0c0902e9e6dfe6e3dc060300030000f9f6edf7f3e8 +f2eee2e3dfd3eeeadefffff3f8f4e8e3dfd3eeeadeefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfe8e4d8 +fdf9ed040000040000040000070300f7f3e7f1ede20e0b02e7e4dd090600e9e6df080500 +e0ddd6e2dfd8fffef7030000f8f5eef6f3ece7e4ddfcf9f2070400030000e9e6dfeeeee6 +080800ecece4e4e4dce1e1d9e0e0d8f0f0e8050500edede5010100f1f1e9d3d3cb090901 +e5e5ddf9f9f1040400efece3030000ebe8dff2efe6f9f6ed030000fefbf2ebe8dfeeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeece0efebe0efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddf3eddfeee8d8f5efe1eee8daefebe0f0ece1f1ece6aca7a1787471 +f3efecfffefff2f0f10f0d10010004010005fffefffffffff3f3f1fffffd000000fffffd +fbfbf9fffffdf8f8f6f8f8f6090907eeeeecfffffdfffffdfffffdf6f6f4fefefcfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfefffd +fefffbfefffdfefffdfffffdfffffdfffffdfffffdfffefafffffaf3f0e9fffff4eceadd +eceadbf1f0deedecdae9e5d91713080400000f0b00ddd9cef2eee3f8f4e9e3dfd4f0ece1 +aaa69b767267f1ede2fffff4eeeadfeeeadff0ece1efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0 +eeece0eeecdfeeecdfeeecddeeecddeeeddbeeeddbedebdceeecddeeecdfedebdeeeebe2 +edeae1050200fffef7f3efe4f1ede1efebdfefebdff0ece0f0ece0f0ece0efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff2f0e4e1dfd3e2e0d4fffff4f9f7eb +dad8ccfffff4030100efede1eeece0f5f3e7e9e7db171509e5e3d7eceade040200f5f2e9 +edeae3faf7f00a0700d1cec70704000c0902030000120f08030000f7f4ed0c0902d2cfc8 +f3f0e9e7e4dd030000efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeceddde9eddcebf0dcf1ead8f6e9e0f3e4e7 +f4ebeca5a7996c745f000300eeebe2f2e7e1f3ebe0eaecd7e4f2f3cee8ff2547a91439bd +001eae00119b001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfe6e2d6f8f4e80b0700dfdbcff2eee2040000ede9ddf4f0e4030100e2e0d4 +f5f3e70a0800faf8ece4e2d6030100fcfaeee0ded2f4f2e6efede10c0a00edebdff1efe3 +fffff4030100050200e9e6ddf8f5ec070400f1eee5e2dfd6f9f6edefece3ebe8df060300 +efece3e9e6dd030000f8f5ec090600dfdcd3030000f0ede619160feae7e0090600ece9e2 +f3f0e9ece9e20a0700e3e0d9030000f2efe8fffff8030000fefbf4030000ede9dee5e1d5 +faf6eaebe7dbdedaceede9ddfffef2f1ede1efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0ece0ede9dd +0a0600f2eee2f0ece0f0ece0e9e5d9e2ded3030000e4e1da030000fffcf5030000100d06 +050200030000070400d7d4cde5e2dbf2efe8f3f0e9090600f2efe8e8e5deefefe7010100 +fffff8eeeee601010014140c030300010100eeeee6050500e4e4dcfffff812120aeeeee6 +d9d9d1010100ebe8df16130a080500030000030000070400eae7deeeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeece0efebe0efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddf3eddfeee8d8f5efe1eee8daefebe0f0ece1f1ece6aca7a1787471f1edea +fffeff010000fffefff9f7fafffeff010004fffffffffffff5f5f5000000fffffffefefe +edededfffffffafafa000000fffffffcfcfcf0f0f0fefefefafafaffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfefffdfefffd +fffffffffffffffffffffffffffefffffffdfffefafffffaf3f0e9fffff6eceadeeceadb +f1f0deedebdcf3efe3f4f0e5040000f1ede2efebe0f0ece1ede9def5f1e6f0ece1aaa69b +767267f1ede2fffff4eeeadfeeeadff0ece1efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0eeece0 +eeecdfeeecdfeeecddeeecddeeeddbeeeddbedebdceeecddeeecdfedebdeeeebe2edeae1 +050200fffef7f3efe4f1ede1efebdfefebdff0ece0f0ece0f0ece0efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefede1f2f0e4f4f2e6e5e3d7e7e5d9e8e6da +e9e7db030100edebdff7f5e9e3e1d5f9f7eb030100f4f2e6f4f2e6030100e2dfd6fffcf3 +e0ddd4030000fffff6030000ebe8dfefece3e7e4dbe3e0d7e1ded50f0c03f3f0e7eeebe2 +e7e4db141108efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeceddde9eddcebf0dcf1ead8f6e9e0f3e4e7f4ebec +a5a7996c745f000300eeebe2f2e7e1f3ebe0eaecd7e4f2f3cee8ff2547a91439bd001eae +00119b001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff4f0e4e8e4d80d0900f7f3e7f7f3e7040000e1ddd1f7f3e7030100fffff4eae8dc +dad8cc0705000b0900f3f1e5dfddd1fffff4e4e2d6eae8dc030100f5f3e7fcfaeed0cec2 +151307030000e1ded5ebe8df0e0b02efece3e7e4dbfdfaf1030000f1eee5030000eeebe2 +fffff6e7e4db030000f7f4ebf9f6edfaf7f0080500e9e6dfe8e5de030000f9f6efe5e2db +f1eee7050200f4f1ea16130cdcd9d2e8e5de030000e1ded7f9f6ed040000eeeadeede9dd +fefaeeeeeadef9f5e9e0dcd0eae6daefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff8f4e8ebe7db040000 +fdf9ede8e4d8fdf9eddcd8ccfffff4030000fffff8030000e4e1da0b0801dddad3e3e0d9 +f9f6efefece5fffff8e4e1daf1eee7eae7e0030000e4e1dafffdf6edede50f0f07e1e1d9 +050500ebebe3e3e3dbe2e2da060600fafaf2010100eaeae2e8e8e0010100e4e4dcfefef6 +010100efece3030000f6f3eaf8f5ecfbf8efefece3e8e5dcf7f4ebeeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff3eddfeee8d8f5efe1eee8daefebe0f0ece1f1ede4aca7a16c6964fffefbeeedeb +010000f8f6f9fffefffbf9fe0e0c0ffefefef8f8f80a0a0afafafaffffffffffffffffff +ffffff111111f3f3f3fffffff2f2f2ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffdfefffdffffff +fffffffffffffffffffffefffffefffffefcfffffbf3f0ebfffff8eceadeeceaddf1efe0 +edebdce5e1d5f0ece1f5f1e6e0dcd1f9f5eafbf7ecdcd8cdf6f2e7f0ece1aaa69b767267 +f1ede2fffff4eeeadfeeeadff0ece1efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0eeece0eeecdf +eeecdfeeecddeeecddeeeddbeeeddbedebdceeecddeeecdfedebdeeeebe2edeae1050200 +fffef7f3efe4f1ede1efebdfefebdff0ece0f0ece0f0ece0efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfe9e7dbefede1e5e3d7fffff4f3f1e5ebe9ddfdfbef +030100f7f5e9dbd9cde7e5d9f4f2e6080600eae8dcfaf8ec050300efece3e7e4dbf5f2e9 +030000e2dfd60e0b02f1eee5f0ede4f8f5ec030000f8f5ec030000eeebe2eae7def8f5ec +030100efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeceddde9eddcebf0dcf1ead8f6e9e0f3e4e7f4ebeca5a799 +6c745f000300eeebe2f2e7e1f3ebe0eaecd7e4f2f3cee8ff2547a91439bd001eae00119b +001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f3efe3e3dfd3040000f3efe3e3dfd3e8e4d8fefaeee3dfd3050300d7d5c9fcfaeef4f2e6 +030100efede1e1dfd3f9f7ebe2e0d4f6f4e8eceade030100eceadef7f5e9eceadef4f2e6 +070500faf8ececeadedbd9cd050300030100030100e8e6daf8f6eaf1efe30d0b00dedcd0 +eceade090700d0cec2f3f1e5f0ede4030000fcf9f0e5e2d9e7e4db030000050200030000 +eeebe2e5e2d9060300f4f1e8e8e5dc030000fbf8eff0ede4e8e4d9130f03e3dfd3e9e5d9 +f3efe3eae6dafaf6eaf1ede1efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfdbd7cbfefaee040000f2eee2 +f3efe3dad6caf9f5e9e8e4d9090600e1ded5030000fdfaf1040100fdfaf1efece3edeae1 +030000f7f4ebebe8dfe9e6ddf6f3ea030000fefbf2d8d5ccecece2010100e3e3d9020200 +ecece2fdfdf3e5e5db0e0e04ecece2010100fdfdf3e7e7dd010100fffff6d9d9cf020200 +e7e4db1a180cf2f0e4dddbcff2f0e4030100f3f1e5e4e2d6eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f3eddfeee8daf5efe1eee8daefebe0f0ece1f1ede4aca7a165625dfffefbfffefc010000 +fffefffffefffffeff010002fffffff7f7f70a0a0af7f7f7fffffff2f2f2fffffff2f2f2 +000000fffffff2f2f2ffffffffffffe9e9e9ffffffefefefffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffdffffffffffff +fffffffffffffffefffffefffffdfefffefdf3f0ebfffff8ede9e0ede9def2eee2eeeade +efebe0f1ede2fffff4e3dfd4eeeadfefebe0f1ede2ece8ddf0ece1aaa69b767267f1ede2 +fffff4eeeadfeeeadff0ece1efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0eeece0eeecdfeeecdf +eeecddeeecddeeeddbeeeddbedebdceeecddeeecdfedebdeeeebe2edeae1050200fffef7 +f3efe4f1ede1efebdfefebdff0ece0f0ece0f0ece0efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff6f4e8efede1f9f7ebd5d3c7eeece0fdfbefdcdacef2f0e4 +030100090700151307050300edebdfebe9dde7e5d90301000b0900040200060400fbf9ed +ebe9ddf9f7eb030100050300030100f7f5e9e4e2d6121004f0eee2f0eee2f9f7eb030100 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeceddde9eddcebf0dcf1ead8f6e9e0f3e4e7f4ebeca5a7996c745f +000300eeebe2f2e7e1f3ebe0eaecd7e4f2f3cee8ff2547a91439bd001eae00119b001cc7 +0738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdffcf8ec +efebdffcf8ecebe7dbf7f3e7f2eee2f1ede1f4f0e4f9f7ebe5e3d7fffff4dfddd1060400 +f2f0e4f0eee2edebdfefede1e9e7dbefede1fffff4e7e5d9eae8dcf6f4e8e5e3d7f4f2e6 +dad8cbf9f7ebf7f5e8e6e4d8f6f4e7eae8dcfbf9ece5e3d7f0eee1e8e6daebe9dcf5f3e7 +fffdf0f8f6eaf3f1e5efece3fbf8efe4e1d8fffef5f3f0e7e5e2d9f9f6edf1eee5eeebe2 +f9f6ede3e0d7fffff6e9e6ddf0ede4f1eee5e4e2d6faf6ebd9d5c9faf6eaefebdfede9dd +f3efe3e1ddd1f8f4e8efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdffdf9ede8e4d8151105e4e0d4efebdf +fbf7ebefebdfefebdf030000efece3060300f1eee5e5e2d90300000a0700030000fbf8ef +e3e0d7f9f6ede4e1d8eeebe2030000efece3f8f5ecf4f4ea010100fdfdf3ebebe1020200 +0101000a0a00010100dcdcd20f0f05e6e6dcebebe10b0b01d7d7cdf5f5eb0b0b01f1efe3 +faf8ec030100030100171509faf8ece7e5d9070500eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff3eddf +eee8daf5efe1eee8dcefebe0f0ece1f1ede4aca89f76736efdfaf5fffffbfffffd010000 +010000010000fffefffcfcfcffffff000000fffffffbfbfbffffffffffffffffff000000 +efefeffffffff6f6f6fffffffffffffcfcfcffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffdfffffdffffffffffffffffff +fffffffffefffffefffffdfefffefdf3efecfffffaede8e2ede9e0f2eee3eeeadffaf6eb +e3dfd4ede9defdf9eee3dfd4ece8ddebe7dcf5f1e6f0ece1aaa69b767267f1ede2fffff4 +eeeadfeeeadff0ece1efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0eeece0eeecdfeeecdfeeecdd +eeecddeeeddbeeeddbedebdceeecddeeecdfedebdeeeebe2edeae1050200fffef7f3efe4 +f1ede1efebdfefebdff0ece0f0ece0f0ece0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeceadeedebdfedebdff1efe3f1efe3f4f2e6e9e7dbf2f0e4f4f2e6 +dedcd0f9f7ebdedcd0e6e4d8f1efe3f2f0e4030100eeece0e6e4d7f0eee2e5e3d6f3f1e5 +e3e1d4f8f6eaeeecdff6f4e8e2e0d3f9f7ebe6e4d7e9e7dbdddbceebe9ddf5f3e6efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeceddde9eddcebf0dcf1ead8f6e9e0f3e4e7f4ebeca5a7996c745f000300 +eeebe2f2e7e1f3ebe0eaecd7e4f2f3cee8ff2547a91439bd001eae00119b001cc70738db +1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfebe7dbe5e1d5 +f2eee2e7e3d7f1ede1f8f4e8e0dcd0ebe7dbd3d1c5fffff4030100030100fefcf0eeece0 +dedcd0f7f5e9eceadefaf8ecdbd9cdf3f1e5e4e2d6f4f2e6dddbcff9f7ebeae8dbf3f1e2 +f2f0e3e0decff7f5e8e8e6d7f2f0e3e3e1d2f9f7eaeae8d9e2e0d3eeecddebe9dcd4d2c3 +f0eee1eae8dbf1efe3ece9e0dcd9d0f5f2e9f3f0e7eae7deefece3e6e3dae6e3daf4f1e8 +ebe8dfdedbd2ece9e0f7f4ebefece3e9e7dbf3efe4efebdff8f4e8f9f5e9dcd8ccf8f4e8 +f8f4e8e8e4d8efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfe9e5d9f0ece0e6e2d6f2eee2eae6daf4f0e4 +e3dfd3f9f5e9eeebe2eae7defffcf3e1ded5f8f5ecebe8dfe7e4dbfffcf3e7e4dbf7f4eb +f3f0e7e3e0d7f7f4ebe8e5dceeebe2e9e6dde9e6ddedeae1eae7defefbf2dad7ceedeae1 +f8f5ecefece3fdfaf1f0ede4edeae1e9e6ddf8f5ecefece3eeebe2ebe8dfeeece0e3e1d5 +edebdff3f1e5e8e6dadcdacef6f4e8ebe9ddeeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff3eddfeee8da +f5efe3eee8dcefebe0f0ece1f1ede4aca89f74716cfffcf7fcfbf7fffffbfbfaf8f8f7f5 +fffffdfffdfef3f1f2fffefffffefffffefffffefffefcfdfffefff3f1f2fffefffffeff +f9f7f8fffefffffdfefffdfef4f2f3fffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffffdfffffdfffefffffefffffefffffeff +fffdfffffdfffffdfefffefff4eeeefffefbede8e2ede9e0f2eee5eeeadffaf6ebdedacf +f2eee3eae6dbf9f5eaf5f1e6f3efe4e4e0d5f0ece1aaa69b767267f1ede2fffff4eeeadf +eeeadff0ece1efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeece0eeece0eeecdfeeecdfeeecddeeecdd +eeeddbeeeddbedebdceeecddeeecdfedebdeeeebe2edeae1050200fffef7f3efe4f1ede1 +efebdfefebdff0ece0f0ece0f0ece0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfedebdff2f0e4f2f0e4e1dfd3f8f6eadbd9cd1e1c100301000301001f1d11 +030100070500141206030100f4f2e6030100ebe9dceceadbfffff3f1efe0eeecdff1efe0 +edebdeebe9dae6e4d7fbf9eae0ded1faf8e9f4f2e5f6f4e5f8f6e9eae8dbefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeceddde9eddcebf0dcf1ead8f6e9e0f3e4e7f4ebeca5a7996c745f000300eeebe2 +f2e7e1f3ebe0eaecd7e4f2f3cee8ff2547a91439bd001eae00119b001cc70738db1c60f3 +1c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeae6dafffcf0f1ede1 +e6e2d6fcf8ece2ded2f9f5e9f3efe3fbf9eddfddd1fefcf0eceadeefede1eceadeefede1 +eeece0e7e5d9eeece0f7f5e9e3e1d5f6f4e8edebdff4f2e6eceaddf3f1e4e8e6d7eae8d9 +f7f5e6ebe9daf0eedfedebdcf2f0e1e7e5d6f8f6e7f2f0e1e3e1d2f8f6e7f3f1e2efedde +e9e7dae6e4d8fcf9f0f6f3eae8e5dcece9e0f2efe6eae7def9f6edf4f1e8e4e1d8f6f3ea +f6f3eaeeebe2e4e1d8f6f3eaf2f0e4e9e5d9f1ede1e3dfd3f4f0e4ebe7dbfbf7ebe8e4d8 +f4f0e4efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff1ede1efebdff9f5e9eae6daebe7dbf2eee2ede9dd +f1ede1f0eee2f4f1e8dddad1f6f3eae8e5dcf0ede4f3f0e7e4e1d8e7e4dbf8f5eceae7de +f1eee50401000401000300000502000502000b0800ebe8dfe4e1d8f9f6edf6f3eae1ded5 +f1eee5ebe8dfe3e0d7f7f4ebfaf7eed4d1c8f4f1e8f2efe6e9e7dbf3f1e5efede1eae8dc +eceadef0eee2eae8dcfefcf0e6e4d8eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff3eddfeee8daf5efe3 +eee8dcefebe0f0ece1f1ede4aca89f726f68fefbf6fffffbf1f0ecfffffbfcfbf9f8f7f5 +fffffdfffefff0eeeffffdfefffefffcfafbfaf8f9fffefffcfafbfffefff3f1f2fffeff +f7f5f6fdfbfcfffefffffefffdfbfcfffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffffdfffffdfffffdfffffdfffefffffefffffefffffdff +fffdfffffdfefffefff4eeeefffefbede8e4ede8e2f2eee5eeeae1e5e1d6fcf8edefebe0 +f2eee3e3dfd4eeeadfeeeadff4f0e5f0ece1aaa69b767267f1ede2fffff4eeeadfeeeadf +f0ece1efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeece0eeece0eeecdfeeecdfeeecddeeecddeeeddb +eeeddbedebdceeecddeeecdfedebdeeeebe2edeae1050200fffef7f3efe4f1ede1efebdf +efebdff0ece0f0ece0f0ece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfedebdfefede1e6e4d8f6f4e8eae8dcf4f2e6e4e2d6f9f7ebefede1e2e0d4f8f6ea +edebdfebe9ddf1efe3f4f2e6f0eee1edebdef1efe0e3e1d2e8e6d7f2f0e1f2f0e1e8e6d7 +f0eedff4f2e3e8e6d7e9e7d8e6e4d5e9e7d8faf8e9d5d3c4f8f6e7efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eceddde9eddcebf0dcf1ead8f6e9e0f3e4e7f4ebeca5a7996c745f000300eeebe2f2e7e1 +f3ebe0eaecd7e4f2f3cee8ff2547a91439bd001eae00119b001dc80030d32064f71851b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff1efe3f0eee2eae8dcf6f4e8e4e2d6f3f1e5e8e6daf4f2e6 +e7e5d9f8f6eae9e7dbf1efe3f5f3e7e8e6dae6e4d8f2f0e3f2f0e3e8e6d7f6f4e5e8e6d7 +fbf9eaf1efe0f6f4e5eeecddf3f1e2e7e5d6f2f0e1eceadbeae8d9e6e4d5f0eedff0eee1 +eeece0ebe9ddf7f5e9e1dfd3fdfbefefede1e1dfd3f8f6eaeeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0 +efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0eeece0eeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff2ece0eee8dcf5efe3eee8dc +e4e0d5f8f4e9eae6ddaba79e6b6861fffff8fffffaf8f7f2fffffaf9f8f4fffffbf6f5f1 +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefcfffefc +fffefcfffefcfffefcfffefcfffefafffefafffefafffefcfffdfefffdfefffdfefffdfe +fff9fbfffdffece6e6b4afacaaa29fa9a29ca9a29abbb4acaeaa9faeaa9faeaa9faeaa9f +aeaa9faeaa9faeaa9faeaa9fafaba0a7a3986e6a5ff9f5eafcf8edeeeadfebe7dcf6f2e7 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeece0eeece0eeecdfeeecdfeeecddeeecddeeeddbeeeddb +eae8d9e9e7d8f0eee1edebdee5e2d9faf7ee040100fffff8efebe0efebdfefebdfefebdf +efebdfefebdfefebdfefebdfeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdeedebdeedebdcedebdcedebdcedebdcedebdcedebdcedebdc +edebdcedebdcedebdcedebdcedebdcedebdcedebdcedebdceeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeebecdc +edf1e0eff4e0f2ebd9f3e6ddfcedf0ede4e5abad9f656d58000200efece3f6ebe5f3ebe0 +e7e9d4e8f6f7cce6ff2749ab1439bd001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfe8e6daf3f1e5f3f1e5eae8dce7e5d9efede1090700030100110f03 +03010018160adfddd1eceade070500edebdff5f3e7e9e7dae7e5d6f0eee1f7f5e6dedccf +ebe9dadcdacdf5f3e4e8e6d9f9f7e8f9f7ead9d7c8fffff3f1efe0e4e2d5efede0e8e6da +fefcf0f5f3e7eeece0e2e0d4f1efe3eeece0ebe9ddeeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0 +efebe0efebe0efebe0efebe0efebe0efebe0efebe0eeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefe9ddebe5d9f6f0e4f4eee2e9e5da +f5f1e6e5e1d8aeaaa184817af0ede6f7f6f1fbfaf5fffffafefdf8fffffafaf9f5fffffb +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffd +fffffbfffffdfffffbfffffafffffafffffafffffbfffefdfffefdfffefffffefffffdff +e5dfdf8e88885b5653756d6a867f79736c64676058716d62716d62716d62716d62716d62 +716d62716d62716d6269655a74706579756aeeeadffffff4efebe0ede9deeae6dbefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfeeece0eeece0eeecdfeeecdfeeecddeeecddeeeddbeeeddbf9f7e8 +e6e4d5efede0eae8dbf0ede4f1eee5030000fffff8f1ede2f1ede1f1ede1f1ede1f1ede1 +f1ede1f1ede1f1ede1f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0efede1 +efede1efede1efede1efede1efede1efede1efede1efede1efede1efede1efede1efede1 +efede1efede1efede1efede0efeddeefede0efeddeefede0efeddeefede0efeddeefede0 +efeddeefede0efeddeefede0efeddeefede0efede0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0edeedee6ead9 +ebf0dcf0e9d7f0e3daf5e6e9e7dedfadafa1717964030600eeebe2ece1dbf0e8ddebedd8 +e5f3f4cde7ff2749ab1439bd001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfedebdff6f4e8e6e4d8e9e7dbfffff3f4f2e6030100fffff3f1efe3eae8dc +f2f0e4080600dedcd0080600fffff4d7d5c9f1efe3f5f3e6edebdff0eee1fffef2e7e5d8 +fffff3ebe9dcf9f7ebe4e2d5e9e7dbf5f3e6dcdacef6f4e7e3e1d5f2f0e4ebe9dde1dfd3 +dbd9cdf5f3e7f1efe3ebe9ddfbf9edebe9ddeeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0 +efebe0efebe0efebe0efebe0efebe0efebe0eeecdfeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff0eadeeae4d8f4eee2f6f0e4ebe7dcf2eee3 +e9e5dac5c1b6e1ded5fffcf3f7f7eff6f6eef5f5ede9e9e1edede5ecebe6f1eee9f1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9f1edeaf1eee9 +f1edeaf1eee9f1eee7f1eee7f1eee7f1eee9f1eee9f1edeaf2ececf2ececf5efeffef8f8 +f3ebe9eae2dffaf2effcf5eff5ece5fdf6eef6f2e7f6f2e7f6f2e7f6f2e7f6f2e7f6f2e7 +f6f2e7f6f2e7fcf8edede9deede9defcf8edfffff4e5e1d6f2eee3f2eee3efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfeeece0eeece0eeecdfeeecdfeeecddeeecddeeeddbeeeddbe7e5d6e7e5d6 +fffff3eeecdff6f3eaeeebe2030000fffff8aeaa9faeaa9eaeaa9eaeaa9eaeaa9eaeaa9e +aeaa9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9eadab9fadab9f +adab9fadab9fadab9fadab9fadab9fadab9fadab9fadab9fadab9fadab9fadab9fadab9f +adab9fadab9fadab9fadab9eadab9fadab9eadab9fadab9eadab9fadab9eadab9fadab9e +adab9fadab9eadab9fadab9eadab9fadab9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9e +aeaa9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9eaeaa9eabac9ca8ac9baeb39f +b5ae9cb5a89fbcadb0b9b0b1989a8c727a65000200f1eee5f4e9e3f0e8ddebedd8e2f0f1 +d3edff2244a61439bd001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeceadee7e5d9f3f1e5fbf9ede5e3d7edebdf030100efede1efede1e0ded2eae8dc +0a0800fffdf1030100eae8dcf3f1e5eae8dcf4f2e6e9e7dbeae8dceceadee2e0d4e9e7db +edebdfefede1dedcd0edebdffaf8ecf6f4e8eeece0eceadefaf8ece7e5d9fefcf0f7f5e9 +f0eee2eae8dcebe9ddf0eee2eceadeeeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0 +efebe0efebe0efebe0efebe0efebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff5efe3ece6daefe9ddf2ece0ebe7dcf1ede2f4f0e5 +e8e4d9fffff6fffff6fffff8fffff8fdfdf5fefef6fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff6fffff4fffff6fffff8fffff8fffffafffefbfffefbfffdfafffefbfffdfa +fffef8fffef8fffdf5fbf2ebfffcf2fffaf0fffbf0fffbf0fffbf0fffbf0fffbf0fffbf0 +fffbf0fffff4fffff4fffff4f8f4e9fffff4ede9def5f1e6f4f0e5efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfeeece0eeece0eeecdfeeecdfeeecddeeecddeeeddbeeeddbf8f6e7edebdceae8db +d8d6c9f6f3eaf4f1e80300006e6b64706c61706c60706c60706c60706c60706c60706c60 +706c60706c60706c60706c60706c60706c60706c60706c60706c606f6d616f6d616f6d61 +6f6d616f6d616f6d616f6d616f6d616f6d616f6d616f6d616f6d616f6d616f6d616f6d61 +6f6d616f6d616f6d616f6d616f6d616f6d616f6d616f6d616f6d616f6d616f6d616f6d61 +6f6d616f6d616f6d616f6d616f6d61706c60706c60706c60706c60706c60706c60706c60 +706c60706c60706c60706c60706c60706c60706c60706c606d6e5e656958696e5a6f6856 +6e61587465687b7273737567646c57000200f9f6edfffaf4f1e9dee5e7d2e0eeefdcf6ff +2143a51439bd001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9 +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efede1fcfaeedddbcfe7e5d9f6f4e8eceade171509e5e3d7f4f2e6f5f3e7f9f7eb030100 +d6d4c8030100e8e6daefede1040100030000030000e7e4dbf5f2e9faf7ee0b0800030000 +030000fffff6f2efe6e7e4db030000030000030000e3e1d5eceadee3e1d40d0b00030100 +fffdf0f4f2e5dddbcef9f7eaeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +efebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdf +f1ebdff1ebdff1ebdfefebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff5efe3eee8dcefe9ddf2ece0ede9deefebe0f5f1e6f7f3e8 +ebe9dddcdaceecece2f0f0e6ecece2f3f3e9ecece2eaeae0eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2 +eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeebe2eeece0 +eeecdfeeecdfeeece0eeece0efebe2efeae4efeae4efeae6f6eeebede5e2e5dddaeae3dd +f6ede6f7eee5f5ece3f9f2e8f3ece2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +dedacfdedacff3efe4e7e3d8f0ece1f4f0e5eeeadfece8ddefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +eeece0eeece0eeecdfeeecdfeeecddeeecddeeeddbeeeddbe5e3d4efeddef3f1e4f6f4e7 +f6f3ead6d3ca16130e030000080400080400080400080400080400080400080400080400 +080400080400080400080400080400080400080400080400070500070500070500070500 +070500070500070500070500070500070500070500070500070500070500070500070500 +070400070400070400070400070400070400070400070400070400070400070400070400 +070400070400070400070500080400080400080400080400080400080400080400080400 +0804000804000804000804000804000804000804000506000105000409000a03000a0000 +0a0000070000050700010900090c01c8c5bce7dcd6f3ebe0f3f5e0e7f5f6d8f2ff1e40a2 +1439bd001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfe2e0d4 +eeece0f3f1e5faf8eceae8dcf4f2e6030100030100030100030100171509e3e1d5fffff4 +0e0c00eeece0f4f2e6f9f6ede3e0d7fbf8ef131007e0ddd4030000f0ede4e0ddd4eae7de +030000f0ede4030000f3f0e7fefbf2e0ddd416130aeceade131104e6e4d7f2f0e30b0900 +dfddd0fdfbeee6e4d7eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdff1ebdf +f1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdf +f1ebdff1ebdfefebdfefecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefe9ddf0eadef2ece0f4eee2f2eee3eeeadfece8ddefebe0f6f4e8 +f0eee2f8f8eef3f3e9ebebe1f0f0e6ecece2e7e7dbedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdeedebdc +edebdcedebdcedebdeeeeadfeeeae1eeeae1eee9e3efe8e2f5eee8fef7f1fef7eff4ebe2 +e9e1d6eae2d7eee8dcf0e9dfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadffffdf2 +fcf8edf7f3e8ece8dde8e4d9f2eee3ede9deeeeadfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0 +eeece0eeecdfeeecdfeeecddeeecddeeeddbeeeddbeae8d9f1efe0f0eee1f5f3e6e8e5dc +f0ede4eae7e2f8f5eeece8ddece8dcece8dcece8dcece8dcece8dcece8dcece8dcede9dd +ede9ddede9ddede9ddede9ddede9ddede9ddede9ddeceadeeceadeeceadeeceadeeceade +eceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeeceadeece9e0 +ece9e0ece9e0ece9e0ece9e0ece9e0ece9e0ece9e0ece9e0ece9e0ece9e0ece9e0ece9e0 +ece9e0ece9e0ece9e0ede9deede9ddede9ddede9ddede9ddede9ddede9ddede9ddede9dd +ede9ddede9ddede9ddede9ddede9ddede9ddeaebdbe7ebdaebf0dcf7f0def9ece3f6e7ea +efe6e7e8eadce4ecd7eaede2fffff6f5eae4eee6dbe4e6d1d5e3e4cfe9ff3456b81439bd +001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff8f6eaf3f1e5 +eae8dcebe9dde7e5d9dedcd0100e02e4e2d6faf8eceeece0e0ded2edebdfe6e4d8050300 +e9e7dbeae8dc030000131009030000030000f4f1ea030000f3f0e9fdfaf3e4e1dafbf8f1 +e5e2db0a0700030000040100030000030000f6f4e8e6e4d7030100fffef1f1efe2efede0 +e5e3d6f2f0e3eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdff1ebdff1ebdf +f1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdff1ebdf +f1ebdfefebdfefecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfede7dbf4eee2f3ece2f1eae0f2eee3efebe0eae6dbebe7dcedebdfeeece0 +e5e5d9e3e3d7e4e4d8e7e7dbf1f1e5f4f4e8eeece0efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeddbeeeddb +eeeddbeeecddefebdfefebe0f1eae2f1eae2f5eee6ebe4dce8dfd8e8dfd8ece3daf6eee3 +faf2e7f2ece0f2ebe1f0ece1f0ece1f0ece1f0ece1f0ece1f0ece1f0ece1e4e0d5e5e1d6 +e9e5daf0ece1f7f3e8f0ece1f2eee3efebe0efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0eeece0 +eeecdfeeecdfeeecddeeecddeeeddbeeeddbf0eedfebe9daeae8dbedebdef2efe6edeae1 +ece9e4e7e4ddf1ede2f1ede1f1ede1f1ede1f1ede1f1ede1f1ede1f1ede1f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f1efe3f1efe3f1efe3f1efe3f1efe3f1efe3 +f1efe3f1efe3f1efe3f1efe3f1efe3f1efe3f1efe3f1efe3f1efe3f1efe3f1eee5f1eee7 +f1eee7f1eee7f1eee7f1eee7f1eee7f1eee7f1eee7f1eee7f1eee7f1eee7f1eee7f1eee7 +f1eee7f1eee5f2eee3f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2f2eee2 +f2eee2f2eee2f2eee2f2eee2f2eee2eff0e0e4e8d7e6ebd7f2ebd9f9ece3f9eaedf2e9ea +eaecdee8f0dbe5e8dddad7ceeadfd9fbf3e8f5f7e2e9f7f8c6e0ff1a3c9e1439bd001eae +00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff0eee2e2e0d4f0eee2 +ebe9ddf0eee2fffdf1030100f2f0e4e2e0d4faf8ece8e6daf5f3e7f5f3e7030100f3f1e5 +030100ece9e0e6e3dcf9f6ef030000fffcf5030000e6e3dceeebe4f9f6efe3e0d9eae7e0 +0c0902efece5e9e6dffcf9f2e8e5dceae8dcf5f3e6eceadd030100e8e6d9e9e7dafaf8eb +e7e5d8eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfefebdff1ebdf +efebdff1ebdfefebdff1ebdfefebdff1ebdfefebdff1ebdfefebdff1ebdfefebdff1ebdf +efebdfeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff0eadef8f2e6f2ebe1ebe4daeeeadff1ede2f0ece1f4f0e5efede1f7f5e9e8e8dc +f0f0e4f4f4e8e6e6daebebdfecece0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddeeeddbeeedd9eeeddb +eeeddbefebdfefebdfefebe2f1eae2efe8e0f3ece4fdf4edf9f0e7eee5dcf1e9def5ede0 +ece6d8eeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadff7f3e8f0ece1eeeadf +ece8ddf8f4e9ddd9cef2eee3efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0eeece0eeecdf +eeecdfeeecddeeecddeeeddbeeeddbe8e6d7f1efe0f8f6e9e0ded1f0ede4f1eee5ece9e4 +f0ede6ede9deede9ddede9deede9ddede9deede9ddede9deede9ddeeeadfeeeadeeeeadf +eeeadeeeeadfeeeadeeeeadfeeeadfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedeae1edeae1edeae3 +edeae1edeae3edeae1edeae3edeae1edeae3edeae1edeae3edeae1edeae3edeae1edeae3 +edeae1eeeadfeeeadfeeeadfeeeadfeeeadfeeeadeeeeadfeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeebecdef0f4e3ecefdcf1eadaf5e8dff5e6e9f1e7e8eceee0 +edf5e0f9fbeee1ded5fdf3eaf2e8dedcdec9edfbfed3ecff2042a61439bd001eae00119b +001dc80030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeeadeede9dde8e4d8f1ede1 +f5f1e5f6f2e6040000f7f3e7efebdff1ede1f0ece0efebdff4f0e4040000f3efe3060200 +f7f3eae4e0d7f7f3ea040000efebe2040000faf6edeae6ddf3efe6040000f1ede4070300 +ebe7dee6e2d9f2eee5040000e9e5da040000efebdff4f0e4040000f2eee2eeeadeeeeade +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfede9ddf2eee2ede9ddf8f4e8 +eeeadefaf6eaf0ece0efebdff1efe2e5e3d6fcfaeddbd9ccf8f6e9f7f5e8e2e0d3f6f4e7 +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfefebdfeeecdf +efebdfeeecdfefebdfeeecdfeae6daf5f3e6efebdfeeecdff8f4e8e1dfd2f9f5e9e7e5d8 +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f1ebdff4eee2ebe4daf5eee4f3efe4eae6dbf5f1e6f5f1e6eeece0eae8dce8e8dce8e8dc +e8e8dceaeadef3f3e7e5e5d9eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeade +eeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeeadeeeebdcedecdaebedd8ebecdaebecda +edebdeedebdeedeae1eeeae1f0ece3f0ece3f3ece4f3ece2f3ece2f2ece0f1ebddf1ebdd +efebe0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0f9f7ebe6e4d8f6f4e8 +e3e1d5f9f7ebe2e0d4f0eee2efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0efebe0efebdfefebdf +efecddefecddefecdbefecdbece9daefecddeae6daf0ece0eeeae1f2eee5fffefaf8f3ed +fffff6fffff4fffff6fffff4fffff6fffff4fffff6fffff4fffff6fffff4fffff6fffff4 +fffff6fffff4fffff6fffff4fffff4fffff4efede1fffff4fcfaeefffff3fffff4fffdf1 +fffff3fffff4fffff4fffff4f7f5e9fffff4fefcf0fffff4fffff4fffff4fffff6fffff4 +fffff6fffff4fffff6fffff4fffff6fffff4fffff6fffff4fffff6fffff4fffff6fffff6 +fffff6f4f1e8fffff6fffff6fffdf4fffff4fffff6fefcf0fffff4fffff4fffff3fffff3 +fffff3fffff3fffff3fffff3fefff3fafdecffffeffffaf1fffafdfff8f7fffff1f1f6e0 +6f7163eeeadff4e7dff7ede1eaebd9e3f1f4d3ebff2444a91439bd001eae00119b001dc8 +0030d32064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfece8dcfffff3ece8dcddd9cdf9f5e9 +e0dcd0262216e5e1d5eeeadee5e1d5f3efe3fffff3e0dcd0090500f1ede1ede9dd040000 +040000090500040000f5f1e8f9f5ec040000120e05040000ede9e0e6e2d9f4f0e70e0a01 +0703000a0600ebe7dcf7f3e8eeeade050100070300d6d2c6f3efe3e4e0d4f6f2e6efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff5f1e5f0ece0e9e5d9e2ded2f1ede1 +e5e1d5ebe7dbfffbefeae8dbf3f1e4e8e6d9fffff2eeecdff1efe2f1efe2e5e3d6eeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdffbf9ece8e6d9eceaddf9f7eaeae8dbefede0edebdef1efe2eeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdf +f4eee2ebe4daf3ece2f4f0e5eeeadfefebe0dedacfe5e3d7ebe9ddeeeee2f6f6eaf0f0e4 +e5e5d9eeeee2eeeee2efede1f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0 +f0ece0f0ece0f0ece0f0ece0f0ece0f0ece0efede0edeedcedeedcedeedcedeedeefede0 +efede1efece3efece3ece8dfece8dfefe8e0f0e9e1f1eae0f1ebdff1ebdfefebdff1ede2 +f0eee2f0eee2f0eee2f0eee2f0eee2f0eee2f0eee2eeece0e7e5d9f0eee2ebe9ddfaf8ec +eae8dcfffdf1e9e7dbefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0efebe0efebdfefebdfefecdd +efecddefecdbefecdbedeadbefecddeae6daf0ece0eeeae1f1ede4fffefaf7f2ecf4efe9 +f4f0e7f4f0e7f4f0e7f4f0e7f4f0e7f4f0e7f4f0e7f4f0e7f4f0e7f4f0e7f4f0e7f4f0e7 +f4f0e7f4f0e7f4f0e7eceadefefcf0fffff3e8e6daf3f1e5fffff4edebdff9f7ebf8f6ea +efede1e3e1d5f2f0e4fffdf1eae8dcf4f2e6f7f5e9f3f1e5f3f1e5f3f1e5f3f1e5f3f1e5 +f3f1e5f3f1e5f3f1e5f3f1e5f3f1e5f3f1e5f3f1e5f3f1e5f3f1e5f3f1e5f3f1e5f5f2eb +f0ede6f4f1eae9e6dff1eee5f3f0e7f6f3eaf5f2e9f3f1e5f3f1e5f3f1e4f3f1e4f3f1e4 +f3f1e4f3f1e4f1f2e4f6faebf0f3e2fcf2e6fceee5ffeff2f0e4e4ebecdab7bca5707163 +eeeadff4e7def7ede1ecebd9e5f0f6d3ebff2444ab1439bd001eae00119b001dc80030d3 +2064f71851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff5f1e5dedacef9f5e9fbf7ebefebdfebe7db +dad6caf1ede1ede9ddf4f0e4e0dcd0e0dcd0fefaeedcd8ccfffff3e8e4d8fffdf4e8e4db +f0ece3f4f0e7e4e0d7f0ece3f1ede4e0dcd3f8f4ebf9f5ece4e0d7ede9e0f2eee5e4e0d7 +efebe2f2eee3f6f2e7d9d5c9fffff3eeeadefaf6eaede9ddfcf8ece6e2d6efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfece8dceeeadefefaeef9f5e9e8e4d8eeeade +f3efe3dbd7cbedebdeebe9dcf0eee1e9e7daeeecdfeeecdfedebdef4f2e5eeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfdad8cbfaf8ebdedccfe0ded1f2f0e3eeecdff6f4e7eceaddeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ebdff4eee2 +ece6daf1ebdff3efe4f3efe4e9e5dac1bdb2b7b5a9b8b6aa9f9f95a9a99fadada3a7a79d +aaaaa0a9a99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99daba99d +aba99daba99daba99daba99daba99daba99ca9aa9aa9aa9aa9aa9aa9aa9caba99daba89f +aba89faba8a1b1aca6b1aca6b1aca6b1ada4b2aba1b2aca0b2aca0b0aca0aaa69ba9a79b +a9a79ba9a79ba9a79ba9a79ba9a79ba9a79ba6a498c0beb2aba99db4b2a6fffff4dbd9cd +f1efe3f0eee2efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebe0efebe0efebdfefebdfefecddefecdd +efecdbefecdbedeadbf0eddeebe7dbf1ede1ede9e0f1ede4fffefaf7f2eceee9e3eeeae1 +eeeae1eeeae1eeeae1eeeae1eeeae1eeeae1eeeae1eeeae1eeeae1eeeae1eeeae1eeeae1 +eeeae1eeeae1f2f0e4e1dfd3efede1f6f4e8e8e6dadcdacef2f0e4e9e7dbe5e3d7f3f1e5 +fffef2f9f7ebe1dfd3faf8ecdfddd1f1efe3edebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfe2dfd8f7f4ed +e7e4ddfcf9f2f1eee5f8f5ece8e5dceeebe2edebdfedebdfedebdeedebdeedebdeedebde +edebdeebecdeeaeedfe7ead9f3e9ddf1e3dafaeaedf1e5e5e1e2d09da28b707163eeeadf +f4e7def7ede1ecebd9e5f0f6d3ebff2444ab1439bd001eae00119b001dc80030d32064f7 +1851b8e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdf +eceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff0ece0f7f3e7e7e3d7f7f3e7e8e4d8fefaee +f0ece0e6e2d6fffbeff5f1e5eae6daebe7dbfffff3e5e1d5f6f2e6e6e2d7fffbf2e6e2d9 +ece8dffffcf3ede9e0faf6edfbf7eeece8dfe3dfd6faf6edeae6dddad6cdfffff6ebe7de +f5f1e6e9e5d9fffff3e1ddd1ebe7dbf6f2e6d9d5c9faf6eaeeeadeefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfeeeadef4f0e4eae6daf2eee2dcd8ccfbf7ebf9f5e9 +f5f1e5f1efe2fffef1f7f5e8dddbcefaf8ebedebdedfddd0f9f7eaeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfebe9dcf8f6e9faf8ebe4e2d5fbf9ece9e7daf3f1e4e4e2d5eeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefe9ddf5efe3efe9dd +f1ebdfeeeadff4f0e5e8e4d9b0aca15c5a4e807e7265655b6b6b61717167727268727268 +6f6f65726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66726f66 +726f66726f66726f66726f66727064707163707163707064707064726f66726f68726f68 +726f6a716c68716c686f6a666d68626e675f6d665c6c655b6a665b736f64727064727064 +727064727064727064727064727064676559706e62656357e1dfd3fffff4f3f1e5fefcf0 +dedcd0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebe0efebe0efebdfefebdfefecddefecddefecdb +efecdbedeadbf0eddeebe7dbf1ede1ede9e0f1ede4fffdf9f7f2ecf1ede4f1ede4f1ede4 +f1ede4f1ede4f1ede4f1ede4f1ede4f1ede4f1ede4f1ede4f1ede4f1ede4f1ede4f1ede4 +f1ede4e2e0d4f9f7ebe9e7dbefede1e3e1d5fffff4e8e6daf5f3e7f7f5e9e9e7dbd1cfc3 +f4f2e6e6e4d8ebe9ddfbf9edf1efe3f0eee2f0eee2f0eee2f0eee2f0eee2f0eee2f0eee2 +f0eee2f0eee2f0eee2f0eee2f0eee2f0eee2f0eee2f0eee2f0eee2f2efe8eae7e0efece5 +e4e1daf3f0e7d7d4cbf7f4ebf3f0e7f0eee2f0eee2f0eee1f0eee1f0eee1f0eee1f0eee1 +eeefe1eaeedfebeeddf4eadeeddfd6f9e9ecfaeeeeeff0dea8ad96707163eeeadff4e7de +f7ede1ecebd9e5f0f6d3ebff2444ab1439bd001eae00119b001dc80030d32064f71851b8 +e2ebffefe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff3efe3f3efe3f4f0e4e4e0d4efebdfe8e4d8f2eee2e7e3d7 +f6f2e6eeeadee3dfd3f1ede1e5e1d5f8f4e8ddd9cdf8f4e8efebe0ebe7dcf1ede2f3efe4 +e7e3d8eeeadfe7e3d8e9e5daf1ede2fbf7eceae6dbf1ede2fefaefe8e4d9e1ddd2f0ece1 +e5e1d5efebdfe9e5d9efebdff4f0e4f9f5e9ece8dcf7f3e7efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff1ede1f6f2e6e3dfd3ede9ddfcf8eceeeaded9d5c9f3efe3 +d9d7cbf1efe3dfddd1efede1f3f1e5eceadeeeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +faf8eccbc9bdfaf8ecf2f0e4e4e2d6eeece0e8e6daf8f6eaeeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeee8dcf5efe3f4eee2f2ece0 +e8e4d9f3efe4ece8ddaeaa9f838077fbf8effffff8fffff8fdfdf5fcfcf4fffff7fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8fffff8 +fffff8fffff8fffff8fffff8fffff6fffff4fffff6fffff8fffff8fffffafffefbfffefb +fefaf7fdf9f6fcf7f3faf5eff9f4eef9f5ecfbf4ecf9f5eaf4f0e5f3f1e5f3f1e5f3f1e5 +f3f1e5f3f1e5f3f1e5f3f1e5fffff4f3f1e57b796debe9ddfffff4efede1dddbcffbf9ed +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebe0efebe0efebdfefebdfefecddefecddefecdbefecdb +eeebdcf1eedfebe7dbf1ede1ede9e0f1ede4fffdf9f6f1ebefebe2efebe0efebe0efebe0 +efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0 +fefcf0d5d3c7fffff4e7e5d9edebdff2f0e4e3e1d5e2e0d4f3f1e5f0eee2fffff4ebe9dd +fffff3f6f4e8e1dfd3e4e2d6eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0efece5efece5edeae3fffff8 +eeebe2f2efe6f0ede4eeebe2eeece0eeece0eeecdfeeecdfeeecdfeeecdfeeecdfeceddf +ecf0e1f1f4e3faf0e4eddfd6f5e5e8f5e9e9edeedca8ad96707163eeeadff4e7def7ede1 +ecebd9e5f0f6d3ebff2444ab1439bd001eae00119b001dc80030d32064f71851b8e2ebff +efe6ddeff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff8f4e8dcd8ccf4f0e4faf6eae6e2d6f7f3e7fffdf1f2eee2dfdbcf +f0ece0f4f0e4f9f5e9e4e0d4f3efe3f4f0e4e7e3d7f7f3e8f2eee3f0ece1f1ede2f3efe4 +dbd7ccfffff4ebe7dcf0ece1e8e4d9dedacff8f4e9f3efe4e3dfd4fcf8edefebe0f7f3e7 +e8e4d8f5f1e5eeeadef1ede1e9e5d9f3efe3e3dfd3efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff8f4e8e9e5d9faf6eaeae6daede9ddece8dcfffcf0e6e2d6fffff4 +d9d7cbfffff4eae8dceeece0efede1f9f7ebebe9ddeeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0e3e1d5 +fffff4e1dfd3e9e7dbe5e3d7efede1eceadef5f3e7eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfeee8dcf2ece0f5efe3f5efe3e5e1d6 +f1ede2efebe0b0aca1605d54fcf9f0fffff8fffff8fafaf2fffff8fffff8fffffafffffa +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefbfffffafffefb +fffffafffefbfffffafffff8fffff8fffff8fffffafffffafffffbfffefdfffefdfffefd +fffdfcfffcf9fffbf7fffaf6fffbf5fffcf4fffef5fffff4fffff4fffff4fffff4fffff4 +fffff4fffff4fffff4faf8ecaba99d6c6a5ef8f6eafffff4e3e1d5f1efe3e1dfd3efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebe0efebe0efebdfefebdfefecddefecddefecdbefecdbefecdd +f1eedfece8dcf1ede1ede9e0f0ece3fffcf8f5f0eaeeeae1eeeadfeeeadfeeeadfeeeadf +eeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadfe5e3d7 +fcfaeee1dfd3f3f1e5f1efe3dedcd0fffff4f2f0e4f2f0e4dfddd1dfddd1f9f7ebd6d4c8 +faf8ecf5f3e7f2f0e4edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfedebdfedebdfebe8e1f0ede6eeebe4d5d2cbefece3 +fffdf4edeae1e7e4dbedebdfedebdfedebdeedebdeedebdeedebdeedebdeebecdee4e8d9 +ebeeddfaf0e4f2e4dbf8e8ebf3e7e7eaebd9a7ac95707163eeeadff4e7def7ede1ecebd9 +e5f0f6d3ebff2444ab1439bd001eae00119b001dc80030d32064f71851b8e2ebffefe6dd +eff2e1e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfebe7dbfaf6eaeeeadee2ded2f7f3e7f0ece0d6d2c6f3efe3fffdf1f1ede1 +dbd7cbf0ece0efebdfede9ddf5f1e5f0ece0ede9dedfdbd0f2eee3fefaefe9e5dafefaef +eae6dbe6e2d7e7e3d8fffff4f0ece1eae6dbeae6dbfaf6ebdfdbd0f7f3e8ece8dcede9dd +eeeadedad6cafcf8ecede9ddf0ece0f6f2e6efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfe2ded2efebdfeeeadef9f5e9ebe7dbf4f0e4ede9ddf3efe3e6e4d8f4f2e6 +dedcd0eceadef6f4e8eeece0f1efe3e9e7dbeeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0efede1f1efe3 +f0eee2edebdffbf9edeae8dcf2f0e4dfddd1eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdff1ebdfede7dbf2ece0f7f1e5e7e3d8f2eee3 +f0ece3aeaaa179766ffffff8f9f8f3fdfcf7fefdf8fffffafffffafffffbfffffbfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffbfffffdfffffb +fffffdfffffbfffffafffffafffffafffffbfffffdfffffdfffefffffefffffbfcfdf9f8 +faf6f5f7f3f0f5f0ecf5f0eaf5f1e8f6f2e9edebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdff5f3e7afada1716f63e4e2d6fffff4eae8dcf4f2e6f9f7ebefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebe0efebe0efebdfefebdfefecddefecddefecdbefecdbefecddf1eedf +ece8dcf1ede1ede9e0f0ece3fffcf8f5f0eaefebe2efebe0efebe0efebe0efebe0efebe0 +efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0efebe0eceadef2f0e4 +e3e1d5eae8dcfffff40301000301000a0800030100fbf9edfaf8eceae8dce5e3d7eeece0 +f7f5e9eceadeeeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0fcf9f2dddad3f6f3ec15120bf1eee5c9c6bd +fffff6ebe8dfeeece0eeece0eeecdfeeecdfeeecdfeeecdfeeecdfeceddfe5e9dae7ead9 +f6ece0f4e6ddfdedf0f6eaeaeceddbacb19a707163eeeadff4e7def7ede1ecebd9e5f0f6 +d3ebff2444ab1439bd001eae00119b001dc80030d32064f71851b8e2ebffefe6ddeff2e1 +e8edd9eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff5f1e5e7e3d7f4f0e4f7f3e7ebe7dbede9ddfcf8ecede9dde0dcd0fcf8ecf0ece0 +f2eee2ece8dcefebdff1ede1ece8dcf1ede2f1ede2f3efe4dedacff9f5eaeae6dbede9de +f4f0e5eae6dbf2eee3ebe7dcebe7dcfaf6ebddd9cef5f1e6e7e3d8ede9ddece8dcf0ece0 +fefaeeece8dce6e2d6f9f5e9e3dfd3efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff6f2e6ede9dd0d09000400000400000e0a00040000f2eee2040200eeece0030100 +f1efe3eceadee5e3d7f8f6eaedebdfeeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0ebe9dd030100eeece0 +f0eee2e9e7dbeceadef5f3e7efede1eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0eeece0efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdff4eee2eae4d8eee8dcf9f3e7eae6dbf3efe4efebe2 +a9a59c6a6760fffff8faf9f4fffffafffffafdfcf8f7f6f2fffffbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfbfefdfb +fefdfbfdfef9fdfef9fdfef9fdfdfbfefcfdfefcfdfefcfdfefcfdfffefffffefffdf9f8 +f7f3f0f3eeeaf0ebe5eeeae1eeeae1eeece0eeece0eeece0eeece0eeece0eeece0eeece0 +eeece0eeece0a4a2967d7b6ffaf8ecf7f5e9efede1f4f2e6e3e1d5efebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebe0efebe0efebdfefebdfefecddefecddefecdbefecdbefecddf2efe0ece8dc +f1ede1ede9e0f0ece3fffcf8f5f0eaeeeae1eeeadfeeeadfeeeadfeeeadfeeeadfeeeadf +eeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadfeeeadfe9e7dbf3f1e5eeece0 +f1efe3030100f9f7ebebe9ddefede1edebdf060400e5e3d7eeece0fcfaeeeceadee7e5d9 +efede1edebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdfedebdf +edebdfedebdfedebdfedebdfedebdfe7e4ddf8f5eeece9e2030000f3f0e7f7f4ebf2efe6 +e7e4dbedebdfedebdfedebdeedebdeedebdeedebdeedebdeebecdef4f8e9ecefdef4eade +f0e2d9f9e9ecf1e5e5e8e9d7abb099707163eeeadff4e7def7ede1ecebd9e5f0f6d3ebff +2444ab1439bd001eae00119b001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dc +eeeddbefebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f3efe3f3efe3040000ede9ddeae6daf6f2e6f0ece0e7e3d7f2f0e4dfdcd30d0a01f1eee5 +e9e6ddf3f0e7e9e6ddf2efe6eae7def8f5eceeebe2f2efe6ebe8dfeeebe2eae7def3f0e7 +eae7deedeae1e4e1d8fefbf2e6e3daedeae1f1eee5e9e6dd050200e9e6ddfbf8efe8e5dc +e7e4dbfffdf4030000f2efe6f3f0e7efece3f7f4ebebe8dfe9e6ddf6f3ead8d5ccfaf7ee +edeae1f1eee5edeae1f0ede4f1eee5e3e0d7f5f2e9eeece0f0ece0fbf7ebeae6daede9dd +fcf8ecede9ddf5f1e5eae6daefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdff3eddfeee8daf5efe3eee8dcefebe0f0ece1f1ede4aca89f +6e6b64fffffafffffbfffffbfffffbfbfaf8020100fdfcfafcfafbfffefff4f2f3010000 +fffeff010000fdfbfcfffefffffefffefcfdfffeff030102fffeff040203f6f4f5080607 +f7f5f6fffefffbf9faf8f6f7fdfbfcfefcfdfffdfefffefffffefff6f4f5fefcfdf8f6f7 +fffefffffefffefcfdfffeff010000fffeff050304e9e7e80d0b0cfffefff9f7f8fffeff +fffeff010000fffeff010000fffeff070506f2f0f1fffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffffd +fffffdfefffdfefffdfefffffffffffffffffffefffffefffffefff8f6f7fdf9f8fffdfa +e7e4dff4f1eaebe8dfeeebe2f0eee2eceadeeceadeefede1f3f1e5eae8dcfffff3dfddd1 +efede1a9a79b757367f0eee2fffff4edebdfedebdfefede1efebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebe0efebe0efebdfefebdfefecddefecddefecdbefecdbeeebdcf1eedfece8dcf2eee2 +eeeae1f0ece3fffcf8f4efe9efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfeeece0f3f1e5e2e0d4f4f2e6 +030100f1efe3f0eee2edebdff3f1e5e5e3d7fbf9ede9e7dbf6f4e8f1efe3e8e6daf6f4e8 +e7e5d9eceadef6f4e8eae8dcfaf8ece1dfd3faf8ecf0eee2eeece0f3f1e5eae8dcf0eee2 +e8e6daf1efe3e5e3d7f8f6eaf8f5eeece9e2edeae3030000ebe8dfeae7deeeebe2eae7de +eeece0eeece0eeecdfeeecdfeeecdfeeecdfeeecdfeceddfecf0e1e8ebdaf7ede1f3e5dc +f6e6e9f4e8e8eeefdda7ac95707163eeeadff4e7def7ede1ecebd9e5f0f6d3ebff2444ab +1439bd001eae00119b001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddb +efebdfefeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfe6e2d6 +f4f0e4040000fffff3e5e1d5efebdfece8dcfffbefeae7defcf9f0030000e4e1d8f2efe6 +f0ede4f6f3eaece9e0e8e5dce0ddd4f1eee5f6f3eae5e2d9f6f3eae4e1d8f3f0e7f2efe6 +faf7eef2efe6e0ddd4f7f4ebeae7def9f6ededeae1070400e9e6dde2dfd6fffff6e9e6dd +e2dfd6030000e8e5dce4e1d8f4f1e8e1ded5e6e3daf6f3eaece9e0fffff6dfdcd3d6d3ca +fffff6d9d6cdf2efe6edeae1ece9e0f0ede4eae8dce4e0d5e4e0d4f1ede1eeeadef2eee2 +e8e4d8eeeadef1ede1efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdff3eddfeee8daf5efe3eee8dcefebe0f0ece1f1ede4aca89f726f6a +fffffafffffbebeae6fffffdfffffd010000fffefffffefffffefffffeff0d0b0cf3f1f2 +010000fffefffffefffffeffedebec171516edebecfffefffffefffaf8f9010000fffeff +fffdfefffefffdfbfcfffefff7f5f6fcfafbfffefff9f7f8fffefffffefffffefffcfafb +f9f7f8fefcfd010000fffefff4f2f3f5f3f4292728f6f4f5f1eff0fffefffffefffefcfd +fdfbfc020001fffefffffdfefffeff010000fffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffeff +fffefffffefffffefffffefffffefffffefffffefffffefffffefffffefffffffffefffd +fefffdfefffffefffffffffffffffffffefffffefffdfbfcfcfafbf1edecfffdfaf3f0e9 +eeebe2e5e2d9f2f0e4eceadef1efe3f2f0e4e9e7dbe7e5d9faf8ecdad8ccfffff4efede1 +a9a79b757367f0eee2fffff4edebdfedebdfefede1efebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0 +efebe0efebdfefebdfefecddefecddefecdbefecdbeeebdcf1eedfece8dcf2eee2eeeae1 +f0ece3fffcf8f4efe9efebe0efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdff4f2e6ebe9ddefede1f2f0e4030100 +e9e7dbefede1f5f3e7efede1edebdffaf8ecd4d2c60c0a00060400030100edebdff3f1e5 +030100eeece0030100030100f2f0e4d4d2c6f6f4e8070500030100050300eeece0eeece0 +fdfbef030100030100030000e1ded7f5f2eb16130cebe8dfe7e4dbe6e3daf2efe6eeece0 +eeece0eeecdfeeecdfeeecdfeeecdfeeecdfeceddfecf0e1e8ebdaf7ede1f3e5dcf6e6e9 +f4e8e8eeefdda7ac95707163eeeadff4e7def7ede1ecebd9e5f0f6d3ebff2444ab1439bd +001eae00119b001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdf +efeae4f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefecddefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff1ede1ede9dd +040000e8e4d8f1ede1efebdff3efe3e8e4d8030000f7f4eb030000f7f4ebeeebe20e0b02 +060300030000fffff6f0ede4dfdcd3090600070400e4e1d8fcf9f0e2dfd6e3e0d7eae7de +f0ede4060300030000070400e6e3daf9f6ed030000040100f0ede4e0ddd4eae7deedeae1 +151209030000f2efe6030000fffdf4f3f0e7030000efece30300000f0c031a170e030000 +efece3f4f1e8e4e1d80c09000d0a01030100f4f0e5fffff3040000f7f3e7e8e4d8f3efe3 +f7f3e7eae6daefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdff3eddfeee8daf5efe1eee8dcefebe0f0ece1f1ede4aca89f6e6b66f3f0eb +f5f4f0fffffdf5f3f4070506fffeff010000f8f8f8f2f2f2fbfbfb090909f8f8f8030303 +fffffff3f3f3ffffffffffff000000fffffffcfcfcf8f8f8ffffff060606f1f1f1fcfcfc +fffffffffffff0f0f0fffffffffffff3f3f3fffffffffffff5f5f5eeeeeeffffffffffff +f6f6f6040404fcfcfcffffff010101ececec000000fffffffffffffafafaffffff000000 +fcfcfc060606f4f4f4fefefe0b0b0bf7f7f7ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffdfefffd +fefffffefffffefffffefffffffffffffffffffefffffffde8e7e3fdfcf7f2efe8f0ede4 +f5f3e7e8e6dae7e5d9eeece0fefcf0e3e1d5f4f2e6e3e1d5eae8dceae8dcefede1a9a79b +757367f0eee2fffff4edebdfedebdfefede1efebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0efebe0 +efebdfefebdfefecddefecddefecdbefecdbeeebdcf1eedfece8dcf2eee2eeeae1f0ece3 +fffcf8f4efe9efebdfefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefebdff8f6eadddbcffbf9ede2e0d40c0a00eceade +d6d4c8f7f5e9e6e4d8fffff3dddbcffefcf0f6f4e8e3e1d5f6f4e8030100f4f2e6030100 +030100f4f2e6fbf9ed040200e9e7db080600e7e5d9fffff4e0ded2060400f2f0e4030100 +f6f4e8ebe9ddf0ede6030000e9e6df030000eae7def3f0e7fcf9f0e8e5dceeece0eeece0 +eeecdfeeecdfeeecdfeeecdfeeecdfeceddfecf0e1e8ebdaf7ede1f3e5dcf6e6e9f4e8e8 +eeefdda7ac95707163eeeadff4e7def7ede1ecebd9e5f0f6d3ebff2444ab1439bd001eae +00119b001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4 +f1eae4f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecddefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdff8f4e8faf6ea0b0700 +040000090500161206e5e1d5f1ede20f0c03eae7de0d0a01ece9e0030000e7e4dbe6e3da +f7f4eb030000edeae10d0a01e1ded5ece9e0060300ebe8dff1eee5efece3fcf9f0030000 +eae7defffff6edeae1030000ebe8df030000f2efe6f6f3eaf6f3eaeeebe2e7e4db030000 +f3f0e7f2efe6030000f4f1e8e8e5dc030000fffcf30c0900e2dfd6e1ded5dcd9d0030000 +fffcf3030000f1eee5e5e2d9eeebe20e0a00d6d2c6f0ece0f5f1e5eae6daf2eee2ece8dc +eeeadeefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdff3eddfeee8daf5efe1eee8daefebe0f0ece1f1ede4aca7a17a7772fffefbfffffd +f5f4f2fffeff010000fffeff010002fffffffffffffbfbfb000000ffffff000000ffffff +fcfcfcfafafafdfdfd0000000e0e0efafafa000000f8f8f8000000ffffffffffff060606 +000000080808f4f4f4fffffffefefe000000030303fffffffcfcfcffffffecececffffff +000000fffffffffffffbfbfbfffffffffffff1f1f1fffffff3f3f3f2f2f2ffffffffffff +f8f8f8fffffff7f7f70c0c0cf7f7f7ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffdfefffdfeffff +fefffffefffffefffffffffffffffffefcfdfdfcfafdfcf7fffff8dad7cefffff4dfddd0 +0503000503000301000301000301000f0d010d0b00eeece0f5f3e7efede1a9a79b757367 +f0eee2fffff4edebdfedebdfefede1efebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0efebe0efebdf +efebdfefecddefecddefecdbefecdbeeebdcf1eedfece8dcf2eee2eeeae1f0ece3fffcf8 +f4efe9efebdfefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefecdddbd9cdfffff4dcdacef0eee2080600f9f7ebfffdf1 +e6e4d8ebe9dde5e3d7fdfbefdfddd10705000301000301000f0d01eeece0070500e4e2d6 +e1dfd3e8e6da110f03f2f0e4030100f5f3e7dfddd1faf8eceeece0f3f1e50301000e0c00 +030100030000030000fffff8030000e7e4dbf1eee5edeae1e6e3daeeece0eeece0eeecdf +eeecdfeeecdfeeecdfeeecdfeceddfecf0e1e8ebdaf7ede1f3e5dcf6e6e9f4e8e8eeefdd +a7ac95707163eeeadff4e7def7ede1ecebd9e5f0f6d3ebff2444ab1439bd001eae00119b +001cc70738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4 +f6e8dff5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfe2ded2e3dfd3040000faf6ea +f5f1e5ede9ddeeeadef6f2e7030000f1eee70b0801e4e1da090600030000030000030000 +120f08e9e6dff7f4ed030000f2efe8f6f3ecdfdcd5fcf9f2f2efe8e7e4dd030000e4e1da +eeebe4e4e1da131009edeae3080500eae7e0ece9e2e3e0d9ece9e2f5f2eb030000f1eee7 +f2efe8030000e5e2dbfaf7f0040100e5e2db030000f1eee7fbf8f1f1eee714110ae3e0d9 +0401000300000e0b04030000040000eeeadef8f4e8f4f0e4e7e3d7eeeadef5f1e5fcf8ec +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +f3eddfeee8d8f5efe1eee8daefebe0f0ece1f1ede4aca7a166635efcf8f5fffffdfffeff +060407fffeffedebf0fffeff000000fffffffcfcfc010101ffffff000000f6f6f6ffffff +fffffffefefe060606f1f1f1ffffff0c0c0cffffff000000ffffff000000fbfbfbffffff +eeeeee191919e9e9e9000000fffffff5f5f5000000fcfcfcfffffffffffff2f2f2030303 +fbfbfbfefefefcfcfcfefefefffffff9f9f9fffffffffffffffffff5f5f5fafafafdfdfd +fdfdfdf5f5f5020202ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefffdfcfffdfcfffffcffff +fefffffefffffffffffffffffbfbf9fffffbe3e2ddfefef6fbfbefddded0e1e2d2f1f2e2 +070500030100070500030100030100f0eee2f1efe3e5e3d7efede1a9a79b757367f0eee2 +fffff4edebdfedebdfefede1efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0efebe0efebdfefebdf +efecddefecddefecdbefecdbeeebdcf1eedfece8dcf2eee2eeeae1f0ece3fffcf8f4efe9 +efebdfefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefecddf4f2e6f1efe3f1efe3e6e4d8070500e6e4d8dddbcfeae8dc +f5f3e7eceadeedebdf0d0b00eeece0efede1e6e4d8030100e9e7db060400fffef2f8f6ea +edebdf030100e9e7db040200ebe9ddfffff4edebdfe7e5d9e4e2d6131105cbc9bdfefcf0 +e8e5def3f0e9e8e5de050200fffff6d3d0c7f7f4ebf8f5eceeece0eeece0eeecdfeeecdf +eeecdfeeecdfeeecdfeceddfecf0e1e8ebdaf7ede1f3e5dcf6e6e9f4e8e8eeefdda7ac95 +707163eeeadff4e7def7ede1ecebd9e5f0f6d3ebff2444ab1439bd001eae00119b001cc7 +0738db1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8df +f5e9dbefebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdffcf8ecf9f5e90b0700e8e4d8f0ece0 +f1ede1f8f4e8e9e5da100d04fffef7030000ebe8e1040100f5f2ebeeebe4eae7e0ece9e2 +e6e3dcf1eee7f9f6ef080500ece9e2e2dfd8eae7e0edeae3f5f2eb030000fffdf6fefbf4 +e5e2db030000efece5030000f4f1eadedbd4fbf8f1eeebe4f3f0e9030000f0ede6eeebe4 +030000edeae3eeebe4090600efece5030000edeae3e7e4ddedeae3030000eae7e00e0b04 +e9e6dff0ede6faf7eeebe7dcf1ede1e8e4d8faf6eaf5f1e5e8e4d8fefaeee0dcd0efebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddf3eddf +eee8d8f5efe1eee8daefebe0f0ece1f1ece6aca7a1777370fffcf9fffdfefffeff010002 +fffefff2f0f5fffeff171717e8e8e8fdfdfd111111f2f2f2161616e8e8e8fffffff4f4f4 +ffffff000000fffffffdfdfd000000f6f6f60e0e0efbfbfb090909000000010101000000 +000000ffffffffffff0d0d0deeeeeeffffffffffffffffffeeeeeeffffff000000ffffff +fafafafffffff8f8f8fcfcfcffffffebebebfbfbfbf8f8f8fffffffafafaf9f9f9fefefe +ffffff000000fcfcfcffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffefffdfefffdfcfffdfcfffffcfffffeffff +fefffffffffffffffdfffffbf4f5efe8e8e0fffff6ddddd1eff0e0ffffefe8e9d9e5e3d6 +030100090700060400f8f6eaf8f6eaf3f1e5f0eee2efede1a9a79b757367f0eee2fffff4 +edebdfedebdfefede1efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebe0efebe0efebdfefebdfefecdd +efecddefecdbefecdbeeebdcf1eedfece8dcf2eee2eeeae1f0ece3fffcf8f4efe9efebdf +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefecddf3f1e5dad8ccfffff4fbf9ed030100edebdffffff4ebe9ddefede1 +030100f0eee2030100eeece0e5e3d7fefcf0030100eceade050300e5e3d7e8e6dae9e7db +110f03e7e5d90b0900ebe9dde9e7dbf1efe3050300fcfaee131105eae8dcf0eee2f8f5ee +030000f6f3ec0b0801e0ddd4f8f5ecf3f0e7e5e2d9eeece0eeece0eeecdfeeecdfeeecdf +eeecdfeeecdfeceddfecf0e1e8ebdaf7ede1f3e5dcf6e6e9f4e8e8eeefdda7ac95707163 +eeeadff4e7def7ede1ecebd9e5f0f6d3ebff2444ab1439bd001eae00119b001cc70738db +1c60f31c55bce0e9fff4ebe2e8ebdaebf0dceeeddbefebdfefeae4f1eae4f6e8dff5e9db +efebdfeceddfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecddefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfe6e2d6e8e4d8040000fdf9edefebdfeae6da +e7e3d7f3efe4030000e8e5de060300f6f3ec030000efece5e5e2dbf5f2eb040100f6f3ec +030000edeae3e0ddd6030000fffff8e7e4ddf4f1eae4e1da030000e9e6dfebe8e1ebe8e1 +17140de4e1da050200eeebe4f9f6efe2dfd8fffdf6e4e1da030000f1eee7eae7e0fffff8 +030000030000eeebe4f1eee7030000f4f1eaefece5f6f3ec030000f6f3ec030000f9f6ef +efece5dbd8cf040000fbf7ebece8dce7e3d7fbf7ebe7e3d7cfcbbffffff3efebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefecddf3eddfeee8d8 +f5efe1eee8daefebe0f0ece1f1ece6aca7a1706c69fffefbfffeffe8e6e70b090c060409 +010005050308000000fffffdfffffd000000fffffd000000fffffdfffffdfffffdfffffd +000000fcfcfafffffd030301fffffd000000fffffd000000fffffdfffffdfffffdfbfbf9 +fffffde1e1dff8f8f6020200fffffdfffffdfafaf8f6f6f4fffffd000000fdfdfbf6f6f4 +fffffdfffffdfbfbf9fffffdfffffdfffffdfffffdfcfcfafffffdfdfdfbfefefcf4f4f2 +000000fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffdfffffd +fffffdfffffdfffffdfffffdfffffdfefffdfefffdfcfffbfcfffdfcfffdfefffdfefffd +fefffdfefffdfefffaeff0eaf6f7effffff4e9eadcdfe0d0e2e3d1e4e5d3fffff2e8e6da +030100efede1f1efe3e2e0d4e8e6daedebdfefede1a9a79b757367f0eee2fffff4edebdf +edebdfefede1efebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdfefebdf +efebdfefebdfefebdfefebdfefebdfefebdfefebe0efebe0efebdfefebdfefecddefecdd +efecdbefecdbeeebdcf1eedfece8dcf2eee2eeeae1f0ece3fffcf8f4efe9efebdfefecdd +efecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecddefecdd +efecddefecdde3e1d5f8f6eaedebdfe2e0d4f7f5e9030100030100030100090700e2e0d4 +efede1f0eee2050300030100040200070500eceade090700f2f0e4e6e4d8faf8ec090700 +e0ded2eceade090700060400030100eceadee6e4d8e3e1d50c0a00030100030000e9e6df +eeebe4030000ece9e0f3f0e7e9e6ddf0ede4eeece0eeece0eeecdfeeecdfeeecdfeeecdf +eeecdfeceddfecf0e1e8ebdaf7ede1f3e5dcf6e6e9f4e8e8eeefdda7ac95707163eeeadf +f4e7def7ede1ecebd9e5f0f6d3ebff2444ab1439bd001eae00119b001cc50838da1c60f3 +1f54bce2e8fff5ebe2ebe9dcecefdeefecdbf1ebdff1eae4f2e9e2f5e9dbf3ead9eeedd9 +ebeedbecedddeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecddeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecddeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdff3f1e4f0eee1030100eae8dbedebdeeeecdff3f1e4 +eceade090900eeeee4010100efefe5edede30101000c0c02010100ecece2e9e9dfeeeee4 +0d0d03010100e6e6dcedede3e2e2d8eaeae0ebebe1f6f6ec010100010100010100e6e6dc +f6f6ec0b0b01e3e3d9f5f5ebe7e7dde3e3d9f4f4eaf3f3e9010100efefe5d8d8ce131309 +eeeee4eeeee4ddddd3101006010100060600010100f5f5ebe6e6dce8e8de010100060600 +060600f5f3e7dedccf0c0a00efede0e6e4d7f3f1e4fbf9ecdedccfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdff0eedfebead8f2f0e1 +ebe9dceeece0edede1f0ede4a9a9a16e6d68fffffbfffffd060606fffffff7f6fbfefdff +fffffffeffff000100fefffd030502fefffd040603fefffdf8faf7f5f7f4fefffd000200 +fbfdfafefffd000100fafcf9060805fefffd000100fefffdf9fbf8eceeeb0a0c09f1f3f0 +121411fefffdfafcf9000100f6f8f5fdfffcfefffde9ebe80b0d0afefffdfefffdf7f9f6 +fefffdf8faf7f5f7f4fefffdf9fbf8fafcf9fefffdfefffdf9fbf8fefffdfefffd050704 +fbfdfafefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffd +fefffdfefffdfefffdfefffdfcfffdfcfffdfcfffdfcfffffcfffffcfffffcfffdfefffd +fefffdfefffbfefffaf1f4ebf1f4e9eceee0f5f8e7e2e5d4f4f7e6e5e6d8eceddfebecde +f1f2e4eaebddebecdefefff1e0e1d3edeee0a7a89a737466eeefe1fffff3ebecdeebecde +edeee0eeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdfeeecdf +eeecdfeeecdfeeecdfeeecdfeeecdfeeece0eeece0eeecdfeeecdfeeecddeeecddeeecdd +eeecddedebdcf0eedfebe9dcf1efe2edebdfefece3fffdf6f3f0e7eeecdfeeecddeeecdd +eeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecddeeecdd +eeecdff8f9ebddddd1edede1f1f1e5ebebdfefefe3efefe3eeeee2e0e0d4fffff4edede1 +e1e1d5e7e7dbf9f9ede2e2d6edede1f4f4e8e7e7dbe5e5d9fefef2e0e0d4dbdbcffffff3 +e9e9dde9e9ddedede1f3f3e7f4f4e8e8e8dcf4f4e8dbdbcff5f5e9ebebe1f4f4eaeaeae0 +deded4fafaf0e7e7dbe9e9dff0f0e4ecece0ecece0eceddfeceddfeceddfeceddfeceddf +eceddfedefe2e9e9ddf6eee1f2e5ddf5e7e7f3e9e7f0efdda9ab95727063f0e9e1f2e7e1 +f6ede4e9ecdbe3f0f6d5ebff2643ab1638bd001eae00119b001cc20a38d61e5fef2253ba +e4e7fff8e9e4eee7ddf0ece0f3e9ddf3e9dff2e9e2f2e9e0f5ead6f2ecd2ebf0d2e8f1d4 +eaefdbeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0 +eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0 +e3e7d9f6faecd9ddcff6faeceaeee0e3e7d9f2f6e8ebefe1eaeee0dee2d4101406ecf0e2 +e6eadce3e7d9000300e7ebddeaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0eaeee0 +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeef2e1e3e7d6e8ecddf2f6e7 +e5e9dbedf3e5ecefe4a6aca2797e77e7ece6fbfffa000300fcfffff0f4f5fcfffff9fdfc +fbfffd000500f9fffd000300f9fffd07100bf3fcf7f6fffaeef7f2f9fffd000300f9fffd +eff8f3000803f1faf5050e09f9fffde2ebe6040d08020b06000300f9fffdf9fffdf3fcf7 +00030009120df4fdf8f3fcf7f9fffdf9fffdf3fcf7000300f4fdf8f5fef9f9fffdf2fbf6 +f9fffdeef7f2050e09eef7f2f9fffdf3fcf7f9fffdedf6f1f9fffdf7fffb0d1611f0f9f4 +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffdf9fffd +f9fffdf9fffdf9fffdf9fffffbfffffbfffffbfffffbfffffbfffffbfffffcfffffcfffd +fcfffbf9fef7e9efe5fcfff6e8eee2e4eadce7eddfe6eddde9eddce9eddce9eddce9eddc +e9eddce9eddce9eddce9eddcebefde999d8c737766eff3e2fcffeff1f5e4e5e9d8e7ebda +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +eaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeedf +e4e8d9f2f6e7e5e9dae3e7d8e2e6d7eef2e4fefff4e8ecdee8ecdde8ecdde8ecdde8ecdd +e8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdd +e8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdd +e8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdd +e8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdee8ecdee8ecdee8ecde +e8ecdee8ecdde8ecdee8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde8ecdde9ebde +edeae5ede8e4e9e2d8fff8eef0e8e5e9e4def5f0ddaba6927b7269efe5e3f4eae8efeae4 +e0e6d8d7e6edddefff263da51738bd001eae00119b001cc20a38d61e5ff12253bae4e7ff +fae8e6eee7dff0ece1f3e9e0f5e8e0f2e8e6f2e9e2f3ead9f1edd4eaf0d4e8f1d6ebeedb +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddfcfdef +cccfbefffff3e5e8d7e8e9db0003000607000003000102001a1d0cd2d3c5eaeddcf6f7e9 +ebeedd151608f0f3e2eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeff2e1e9eddcecefdeeff3e2e0e2d4 +e8ecdee5e7daa1a49964655dfefffafffffaf4f6f1f1f1effefffdf6f6f4fefffdfcfffd +e6ebe5fcfffbfcfffbe3e8e2fcfffbf8fdf7fcfffbfcfffbf1f6f0f3f8f2fcfffbfbfffa +fcfffbfcfffbeef3edf2f7f1fafff9fafff9fcfffbf7fcf6fcfffbfcfffbfcfffbfcfffb +e6ebe5fcfffbf6fbf5fcfffbfbfffaeef3ed121711fcfffbfcfffbf5faf4fcfffbeff4ee +fcfffbf6fbf5fcfffbeef3edfcfffbfcfffbf8fdf7fcfffbeef3ed000200fcfffbfafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9fafff9 +fafff9fafff9fafffbfcfdfffcfdfffdfcfffcfdfffdfdfffcfefdfdfdfdfcfefbfafbf6 +fefffaf9faf2fefff6edefe4e6eadcebede0f3f5e7ecefdeecefdcedeedcecefdcedeedc +ecefdcedeedcecefdcf8f9e7a5a895717260e8ebd8f9fae8ebeedbeeefddeef1deeceddd +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddf +ebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedde3e4d6 +eff2e1f0f1e3f7fae9f0f1e3ebeeddfcfdefebeeddeeefe1edf0dfeeefe1edf0dfeeefe1 +edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1 +edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1 +edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1 +edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1 +edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1edf0dfeeefe1eeeee2f5f0ec +f4efe9e9e5d9f8f6e9ebe8dfedebdffbf6e0b5af996e645aefe4e0f6eeebdeded6f8fff2 +e0f1f8d3e3ff3248ae1738bd001eae00119b001dc50739da1c60f31f54bee2e8fff7e9e8 +ece7e1efece5f2e9e4f2e8e6f1e8edf1e8ebf3e8e4f1eae0eaeee0eaeee0efecddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbe9dfd3faf3e3 +f4eadef7f0e0f6ece0e5decefff8ecfdf6e6e9dfd3f4edddf0e6daede6d6fffaeee7e0d0 +e8ded2e8e1d1f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf1eadaf1ebdbf4edddf4eedeebe3d6f6f0e2 +f3ebe0b0a99f847b72f3ece4fff9f4fffdfafffcfaf7efedfffcfbf4ece9fffdfafffefa +fffcf8fffefafdf8f4fffdf9fffefafbf6f2f9f4f0fffefafffefafffcf8fffefafef9f5 +fffefafffefafffefafffefafffefafffbf7fffefafef9f5fffefafffdf9fffbf7fffdf9 +fffefafffcf8f8f3effffefafffefafaf5f1040000fffefafffefaede8e4fffefaf6f1ed +fffdf9fffbf7fffefafdf8f4fffefafdf8f4ece7e3100b07fffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefafffefa +fffefafffdfbfffcfffffcfffffbfffffcfdfffcfdfffdfbfffcfbfffdfafbf2edfffef6 +f1e8e1f7f0e6f7eee5f8f2e6f1e9def3ebdef0e9d9f0e9d7f1e8d7f0e9d7f1e8d7f0e9d7 +f1e8d7f0e9d7f0e7d6afa8967c7362f5eedcfffeedf0e9d7f9f0dff0e9d9f3eadbf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdb +f3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbf3e9ddf2ebdbfff5e9f3ecdc +e8ded2f1eadaf4eadef6efdffffdf1fffbebf1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9 +f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9 +f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9 +f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9 +f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9 +f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e9d9f1e7dbf0e8dbf1eae0f1ede1 +e7e6d2edefd9e3e4d4e8e9d7efeed0aca88b6f6657fffdf4e1ddd4fffff4d2e0c9ddf1f0 +def1ff21399d1738bb001eae00119b001ec3043ad81a61f11c56bae0e9fff4ebe4e9e9dd +edeee0efebe0f1eae4efe9edf1e8edf2e8e7f1eae4eaede6eaede6f2e9e2f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff4e5defff3eae8d9d2 +f3e5dcf5e6dffff6edfff0e9e3d5ccf6e7e0f5e7defff0e9fff3eae8d9d2faece3fff2eb +faece3f6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff1e4dbf6eadef5e8dff6e9e0f4e7defff3ebf7eae4 +b5a8a270625ffff7f6fffbfbfffbfbfffafdfff1f4fffafdfffafdfffbfdfffafaf0e4e4 +fffbfbfffbfbfff4f4fff9f9fffbfbfffbfbfdf1f1fff8f8fef2f2fffbfbfffbfbece0e0 +fffbfbfbefeffffbfbfff7f7fffafafcf0f0fffbfbfffbfbfcf0f0fffbfbfcf0f0fff7f7 +fcf0f0fffbfbfffbfbf3e7e7fffbfbfffafafffbfbfffbfbfffbfbfffbfbf5e9e9fffbfb +fffafafffbfbfffbfbfff5f5fffbfbfffbfbf6eaeafffbfbfffbfbfffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafafffafa +fffafcfff9fffff8fffff9fffff9fffff9fefff9fefff9fcfff9fcfff7f7fffbfaecdedd +cdbfbcb4a6a3ab9e98a69993b9aca4b4a69db4a69db4a69db4a69db4a69db4a69db4a69d +b4a69db8aaa19e908783756cfef0e7fffcf3f3e5dcfaece3ebddd4f6e8dff6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0 +f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff6e7e0f6e8dff8e9e2f3e5dcf2e3dc +f6e8dff4e5def8eae1feefe8f4e6ddf9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3 +f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3 +f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3 +f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3 +f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3 +f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f9ebe2f9eae3f8ebe3f0e9dff3f1e4eff1db +f3f5dfebeeddeff0dee9e9cdaca88d746c5fece3dcf0ebe5dfe2d7e1f0dbe7fbfce9feff +2942a61738bd001eae00119b0020be033cd31963ea1b58b3dfecfff3eedae8ecd3ebf1d5 +eeeed6efecdbefeae4efeae7f2e9e2f1eae2eaede4ebece7f2e8e7f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7fcecefeededff6e6e9ebdbdc +fff2f5e5d5d6fff0f3ffeff0ffeff2f5e5e6f0e0e3eddddef8e8ebecdcddfff4f7edddde +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e8e8f9ebeaf2e4e4f3e5e5f4e6e6f9eaedeadbdeae9fa4 +85767dfffafffff9fffff7fffff5fffff9fff8e8f5fff9fffef1fbfffafffffafffff6ff +fffafffffafffff8fffff6fffdf0fafffafffff5fffffafffffafffff5fffffafffff9ff +fffafffff7fffffafffff2fcfffafff8ebf5fffafffffafffff4fefffafffff9fffffaff +fffafff4e7f1fffafffffafffffafff7eaf4fffafffffafff2e5effffafffffafffff3fd +fff7fffff9fffffafffff6fffaedf7fffafffff8fffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffaff +fffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffffafffff9ff +fff8fffff8fffff8fffff8fffff9fffff9fffff9fffff9fffff9fff1e2e97e6f765b4c51 +6e5f6488797e7e6f7478696c79696c79696c79696c79696c79696c79696c79696c79696c +77676a7b6b6e7b6b6ee7d7dafff7faefdfe2fff1f4fbebeef6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7 +f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7f6e6e9f6e6e7eddde0f6e6e7fff2f5f8e8e9 +f1e1e4fff4f5fffafdfff5f6f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5 +f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5 +f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5 +f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5 +f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5 +f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f4e4e5f4e4e7f3e5e5eae2dfece9e0ebecdcecefde +e8e9e1eeeee4e6e5d1bab5a2756c67f7eeefe9e5e6e4e6e3e3f1e4f1ffff8497d93850ba +1737be001eae00119b001fc0043bd31963ea1b58b1dfecfcf3efd6e8edcdebf2d1eeefd0 +efedd6efebe0f1eae4f3e9e0f2e9e0ebece4ebece6f1e9e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7e7dbdbfbefeffff5f5f9ededf0e4e4 +f4e8e8f2e6e6eadedeede1e1f5e9e9fff7f7ede1e1f5e9e9faeeeef0e4e4fcf0f0f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f2e8e7f2e8e6f4ece9ece2e0f0e8e5f4eae9f4eceaece2e3c3babbf1e6ea +eee5e8f8edf3dcd3d8fff5fdf9eff7fff4fcf4eaf2f6ecf4fff6fbf8eef6f4ebf0e3d9e1 +fffbffece2eafff7fcfcf2faf2e9eefff9fffbf2f7ece2eafbf2f7f8eef6ebe2e7fcf2fa +ede4e9fbf1f9f5ecf1fffbfff1e8edf5ebf3ede4e9fbf1f9f4ebf0f3e9f1f4ebf0f5ebf3 +f0e7ecfaf0f8eae1e6fffaffe9e0e5efe5edfffcfff7edf5faf1f6e9dfe7f3eaeff4eaf2 +f6edf2fbf1f9faf1f6f9eff7faf1f6f5ebf3efe6ebf5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3 +f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ecf1f5ebf3f5ebf3f5ebf6 +f5ebf6f6eaf6f5ebf4f6eaf4f5ebf3f6ebf3f5ecf1ebe0e6fffcfffdf2f6fffcfdfff5f6 +f7eeefece2e3f0e6e7f5ebecf6eaecf6eaecf6eaecf6eaecf6eaecf6eaecf6eaecfef2f4 +fdf1f3eee2e4fffbfdfffbfdeee2e4f1e5e7efe3e5f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7 +f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f3e7e7f9ededf2e6e6f7ebebebdfdfede1e1 +fcf0f0dfd3d3b8acacb3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7 +b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7 +b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7 +b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7 +b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7 +b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b3a7a7b2a8a6b3aca6aeaca0acad9babac9aababa1 +b2b2a6b2af9ca19b8b6d645feee4e5fbf5f9f5f7f4ecf8ec9aacb68d9fe1283fa91738bd +001eae00119b001dc90539db1a61f11c56b7dfebfff3eedae8edcfebf2d1eeefd0f1ecd6 +f1ebdff2e9e2f5e8dff3e9dfeeebe4ebece4eceddfeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbf3f4e2dedfcde6e7d5e0e1cff2f3e1e4e5d3 +edeedcf2f3e1eaebd9f7f8e6e2e3d1eaebd9ebecdaffffefe1e2d0e7e8d6eceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbe8ebd8ecf1dde6e9d6ecf1ddeef1e0eaeeddf3f6e5e6ead9fffff3fdfff2 +fffff4fefff4fafcf1fefff6fbfdf2f9fcf1fcfff4eef2e4fefff6fefff4fefff6fafef0 +f6f9eefefff4fefff6edf1e3f5f8edfefff4fefff6fefff4fafdf2fefff4f6f9eefefff4 +fefff6f9fdefe7eadffcfff2fefff6fefff4fefff6f2f6e8fefff6fefff4fcfff4fefff4 +f8fbf0fefff4f1f4e9fefff4fefff6f7fbedeff2e7fefff4fefff6fefff4fefff6f8fcee +fefff6fafef0fefff6eaeee0fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4 +fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff4fefff6fefff6fefff8fefffa +fffffafefff8fffff8fefff6fffff6fefff6f5f7ecfefff4f4f6e9fefff3fafceefcffef +fffff1fffff1fffff3fffff3fffff3fffff3fffff3fffff3fffff3fffff3fffff2fffff3 +fbfceef4f5e7f4f5e7eff0e2eceddff1f2e4ecedddeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddbeceddb +eceddbeceddbeceddbeceddbeceddbeceddbeff0dee1e2d0f0f1dfeeefddeceddbdfe0ce +9899875f604e6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d +6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d +6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d +6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d +6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d +6e6f5d6e6f5d6e6f5d6e6f5d6e6f5d706f5d787360716c56706f516f6f536e6d5973705d +756f5578715784786ceadfd9e4dcd9fffff6a9b5a199abadddedff3248ad1738bb001eae +00119b0019d30835e61c5efb1e54c0e0e9fff4ece1e9ebd5ecf0d7efedd4f1ecd8f2e9e0 +f3e8e4f6e7e0f6e7e0f1eae4ecece2ebeedbeaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8e6e9d4f1f6dff0f3def1f6dfe4e7d2f8fde6e6e9d4 +e3e8d1ebeed9eaefd8e7ead5e7ecd5f3f6e1e3e8d1e9ecd7f2f7e0ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8e7efd8edf5dde5edd6eaf2dbe3ebd4dbe3ccedf5def4fce5e3ebd6f2fae5e0e7d5 +e7eedce8efdfe7eedee9f0e0eaf1e1f1f8e6ecf3e1e5ecdaecf3e1e6eddbe7eedcf0f7e5 +eaf1dfe6eddbf4fbe9e9f0dee8efddeef5e3e5ecdae6eddbf1f8e6ecf3e1e7eedce7eedc +eaf1dff5fceaf4fbe9ebf2e0dde4d2e2e9d7fbfff0d7decceaf1dfe4ebd9e5ecdae3ead8 +ebf2e0f1f8e6d8dfcde6eddbecf3e1eff6e4e9f0dedfe6d4eef5e3edf4e2dbe2d0f2f9e7 +e5ecdadfe6d4faffefd3dac8e9f0dee7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedc +e7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedce7eedee7eddfe7eddfe7eddf +e7eddfe7eedee7eedee7eedee7eedeeef5e3eaf1dfdce4cff5fde8e8f0dbe7efd8eaf2db +e7efdaeaefdbeaefdbebeeddeaefdbebeeddeaefdbebeeddeaefdbe8ebdaedf2def9fceb +e2e7d3eaeddcf2f7e3e4e7d6e6ebd7ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8eaedd8dde2cbf4f7e2edf2dbe4e7d2ebf0d9e3e6d1 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9eaefd8ebeed9 +eaefd8ebeed9eaefd8ebeed9eceed8f5f0ddede7d1f2eed1f4f0d5f2ecdcede7d7eae3c9 +f7ecd6f2e4dbfaebe8fffcfaaaa7a0959e8bedfbfeedf9ff2a3da31738bb001eae00119b +021de8052ced235fff1c4cc8e8eafff0e1e4f1eee5eceddff1ebddf2eadff3e8e6f5e7e7 +f9e5e4f8e6e2f2e8e6efeae4ebebdfeaeddcebecdeeaeddcebecdeeaeddcebecdeeaeddc +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +ebeddfeaeeddeaeedfeaeedfeaeedfeaeedfeaeedfeaeedfeaeee0eaeee0eaeee0eaeee0 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2 +eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede2eaede4eaede4eaede2eaede2 +eaede2eaede2eaede2eaede2eaeee0eaeee0eaeee0eaeee0eaeee0eaeedfeaeedfebeddf +ebede0ebede0ecece2ebede0ecece2ebede0ecece2ebede0ecece2ebede0ecece2ebede0 +ecece2ebede0ecece2ebede0eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeeddeceddfebeedd +eceddfebeeddeceddfeeecdfece2d9fef1e8f2e9daf0e9d9f7eee9f5ece7ece0d4fceee5 +f6e2e4fff2fdb9a9b3aba2a7edf0e9f7ffff959ee12a3ba71a38be001faf00129c0012db +0c2eef255dff2451cee4e5fff0e1e4edeae3f7f8eaf4eee0f5ede2f5ece7f6ebe9fce9e2 +fbeae0f5ede2f2eee3f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f0eee2 +f0eee2f0eee2f0eee2f0eee2f0eee2f0eee2f0eee2f0ede4f0ede4f0ede4f0ede4f0ede4 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede6f0ede4f0ede6f0ede6f0ede6f0ede6f0ede6f0ede4f0ede6 +f0ede4f0ede6f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0ede4f0eee2f0eee2f1ede4 +f1ede4f1ece6f1ede4f1ece6f1ede4f1ece6f1ede4f1ece6f1ede4f1ece6f1ede4f1ece6 +f1ede4f1ece6f1ede4f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2f1ede2 +f1ede2f1ede2f3ece4ede2e0f3e8e4fff8efe7ded7ede4e5f1e7e8fff6f2ebdcd9fff8ff +bba6b5ad9cacebe4ecfefffb919aab9fa9f03648b41a37bf001eae00129c031ed11339e4 +1d58f22150bce7ecfff7ede3e3e4d2ebf0d9ececd4edebd4edead9efe9d9f4e8d2f3e9ce +edecd0ececd4f1e8d9f3e6ddf3e6ddf3e6ddf3e6ddf3e6ddf3e6ddf3e6ddf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf0e6ddf0e6dd +f0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6dd +f0e5dff0e6ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dff0e5dff0e5dff0e5dff0e6ddf0e5dff0e6dd +f0e5dff0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf0e6ddf2e5ddf2e5dd +f2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5ddf2e5dff2e5dd +f2e5dff2e5ddf2e5ddf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dcf2e5dc +f2e5dcf0e5dff8edebf2eae7e3dcd4fffbf5eae6e7f0eaece8e0ddfffcfab5a5afbcabbb +e6dae6fffeffa7aea69caab5d6e5ff2a3fa81738bd001eae00129c0018b90932cc1958e3 +1449a7eaf2fff2ecdce2ead3e7f4daedf2dbeef1dceef1e0eff0def4f0d7f2f1d3edf4d3 +eef2d7f5f0ddf7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f7ede3f6eee3f7ede3 +f6eee3f7ede3f6eee3f7ede3f6eee3f7ede3f6eee3f7ede3f6eee3f7ede3f6eee3f7ede3 +f7ede3f7ede3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3f9ece3 +f9ece3f9ece3f9ece3f9ece3f7ede3f7ede3f6eee3f7ede3f6eee3f7ede3f6eee3f7ede3 +f6eee3f7ede3f6eee3f7ede3f6eee3f7ede3f6eee3f7ede3f7ede3f7ede3f7ede3f9ece3 +f7ede3f9ece3f7ede3f9ece3f7ede3f9ece3f7ede3f9ece3f7ede3f9ece3f7ede3f9ece3 +f7ede3f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1f7ede1f9ede1 +f6ede4faf5efd6d6cefdfff2e9ece1e4e6e3eceeebfffff6b3b0a9a89fa4e6dfe7fffdff +aaafab9eaf9ddff7f7e3faff2642a31639bb001eae00119b0024b60e3dc92e73f21c55ac +eaf9ffe2e3d3e1f0dde4f7e4e1efe0e2eee2e2ede9e3ece7e6ecdee6eed9e1f0d9e2f0d9 +eaefdbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeceddbebeedbeceddbebeedb +eceddbebeedbeceddbebeedbeceddbebeedbeceed9ebeed9eceed9ebeed9eceed9eceed9 +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddbeeeddb +eeeddbeeeddbeeeddbeeeddbeceed9ebeed9eceed9ebeed9eceed9ebeed9eceed9ebeed9 +eceddbebeedbeceddbebeedbeceddbebeedbeceddbeceddbeceed9eceed9eeedd9eceed9 +eeedd9eceed9eeedd9eceed9eeedd9eceed9eeedd9eceed9eeedd9eceed9eeedd9eceed9 +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddb +eeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbeceddbeeeddbebeedd +e2e8daf5ffefd2e0c9e5f4dfe8f6e9edf9eda7b39f99a28ff0f3ecfcfffba3aaa29dae9c +c4e2c0e7fffd91b4da2145991339b8001dad00119b001eb40027b8135be3114fb2e0f3ff +ebeff2e7f9fdd8eff5dceefadcedffdcecffddebffe2ebfce0edf6dceff6dbf0f5dfeef3 +e2edf3e2edf3e2edf3e2edf3e2edf3e2edf3e2edf3e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e1eef4e1eef4e1eef4e1eef4e1eef4e1eef4 +e1eef4e1eef4e1eef4e1eef4e1eff2e1eff2e1eff2e1eff2e1eff2e1eff2e1eff2e3eef4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4e4edf4 +e4edf4e4edf4e3eef2e1eff2e1eff2e1eff2e1eff2e1eff2e1eff2e1eff2e1eff2e1eef4 +e1eef4e1eef4e1eef4e1eef4e1eef4e1eef4e1eef4e3eef2e3eef0e3eef2e3eef0e3eef2 +e3eef0e3eef2e3eef0e3eef2e3eef0e3eef2e3eef0e3eef2e3eef0e3eef2e3eef2e3eef2 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4 +e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e3eef4e1eef4e5f4fb +e8f9ffdbefeed3e7e8f1ffff9caeb890a2a4ecfafdf7ffff8e97a896a4afe8ffffe7fffd +68949787b2e91b45a71239bc001dad00119b0029d90033de165fff2b6aebc7dcffe7ecff +daedffcde4ffd9ecffd9ebffd9e9ffd9e9ffdee9ffdcebffd8edffd5eeffd4edffd4ecff +d4ecffd4ecffd4ecffd4ecffd4ecffd4ecffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd4eeffd4eeffd4eeffd4eeffd4eeff +d4eeffd4eeffd4eeffd4eeffd4eeffd4eeffd4eeffd4eeffd4eeffd5eeffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edffd7edff +d7edffd7edffd5eeffd4eeffd4eeffd4eeffd4eeffd4eeffd4eeffd4eeffd4eeffd4eeff +d4eeffd4eeffd4eeffd4eeffd4eeffd4eeffd5eeffd5eeffd5eeffd5eeffd5eeffd5eeff +d5eeffd5eeffd5eeffd5eeffd5eeffd5eeffd5eeffd5eeffd5eeffd5eeffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edff +d5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd5edffd7edffd5e7ffc7d7ff +e2f5ffe9feff8ea1e3a2b4f6dcecffebf7ff929bdea9b3fadeedffe7feff85a8ce88b3ea +d0fbff1842ca1036c5001cac00119b0018c8083ae7175aff114bda354eb2394695223b8f +2f4aa32c44a62c43ab2c42b12c42b12f42a92f43a42b45a42846a62545aa2545ac2545ac +2545ac2545ac2545ac2545ac2545ac2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2344ab2344ab2344ad2344ab2344ad2344ab2344ab +2344ab2344ab2344ab2345a92345a92345a92345a92345a92345a92444ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab2444ab2643ab +2444a92345a92345a72345a92345a92345a92345a92345a92345a92344ab2344ab2344ab +2344ab2344ab2344ab2344ab2344ab2444a92444a72444a72444a72444a72444a72444a7 +2444a72444a72444a72444a72444a72444a72444a72444a72444a92444a92444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab +2444ab2444ab2444ab2444ab2444ab2444ab2444ab2444ab2643ab2d44ac2f45ab2b43a7 +243da12e44b1253ca6273da23245ab2d3eaa2e40ac2439a22642a32a4ea41f49ab1d47cf +0a32c81235c5001ba7000f970023be0530ca1140d81845d41e41c11d3bb5183ab5173bb6 +1839ba1839bc1839be1839be1839ba183ab8173ab8173aba1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439be1439bd1439be1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd1638bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd1439bd +1439bd1439bd1439bd1439bd1439bd1439bd1439bd1638bd1738bd1738bd1738bb1639bb +1737be1738bd1738bb1738bb1836bc1637bc1637bc1538ba1339b81239bc1137c61336c6 +0a24ac071c9c0013930016a2001ca80023af0125b10023af0020ac0020ac0021ad0021ad +0021ad0021ad0021ad0021ad0021ad0021ad0020ae001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf001faf +001faf001faf001faf001eae001eae001eae001eae001eae001eae001eae001da9081d9d +061592000f8c00129a001199001098000f97000e96000e96000f97001098001098001098 +00109800109800109800109800109800109800109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a00109a +00109a00109a00109a00109a00109a00109a00109a00109a00109a000f97001393000f8c +000c89 +end +%%PageTrailer +%%Trailer +%%EOF diff --git a/doc/doc.tex b/doc/doc.tex new file mode 100644 index 000000000..671b2ef5c --- /dev/null +++ b/doc/doc.tex @@ -0,0 +1,991 @@ + +\documentclass[12pt]{article} + +\usepackage{a4, epsfig, times, fancyhdr} +%\usepackage[T1]{fontenc} + +\nonstopmode + +\hbadness=2000 +\vbadness=2500 +\clubpenalty9000 +\widowpenalty9000 +\tolerance=9999 +\textheight=24cm +\footskip=3\baselineskip +\lefthyphenmin=3 +\parindent=0pt +\parskip=0.5\baselineskip +\hyphenation{ } + +\pagestyle{fancy} +\renewcommand{\headrulewidth}{1pt} +\lhead{\scriptsize V \number\year -\number\month -\number\day} +\chead{} +%\rhead{} +\rhead{\thepage} +\lfoot{} +\cfoot{} +\rfoot{} + +\renewcommand{\topfraction}{1.0} +\renewcommand{\bottomfraction}{1.0} +\renewcommand{\dbltopfraction}{1.0} +\renewcommand{\textfraction}{0.0} +\renewcommand{\floatpagefraction}{.5} + + +\newcommand{\gpsbabel}{{\sc gpsbabel}} +\newcommand{\bsl}{$\backslash$} + + + +\begin{document} + + +{\center +\Large \bfseries The \gpsbabel\ Manual\\[5mm] +Version 0.0.2\\[10mm] + +{\rm \normalsize Principal developer:}\\ +\large Robert Lipe\\[2mm] +robertlipe@usa.net\\ +} + +\tableofcontents + +\newpage + +\section{What \gpsbabel\ is} + +{\bfseries \gpsbabel\ is a conversion utility for a large and still increasing number of GPS related formats that represent waypoints, track points and route points.} + +There are simply too many and annoyingly different file formats to hold waypoint, route and track related information in various programs used by computers. Even though there are some promising attempts to create format standards, e.g. GPX as an XML variant, to carry all data types, there are too many programs that don't understand them yet and too much existing data that are in alternate formats. + +\gpsbabel\ is based on an extensible foundation so that it is quite easy to add new formats. Most file formats implemented so far have taken less than 200 lines of reasonable ISO C code, so they can be stamped out pretty trivially. If you would like to contribute new features, see appendix~\ref{HowToContribute} + +\gpsbabel\ is designed for simple command line invocation for all supported platforms. For users not familiar with the command line (read: many Windows users) there is a mouse pitchforker's GUI interface to ease its use (see section~\ref{GUI}). A full fathoming of \gpsbabel 's features will need some command line familiarity, though. + +\gpsbabel\ is released under the GNU general public license. For further details, see appendix~\ref{GPL}. + + +\subsubsection*{What \gpsbabel\ is not:} + +\gpsbabel\ is not intended to {\em create} any GPS related data, like waypoints or tracks. It does not support uploads or downloads of maps. + + + +\section{General usage: the command line interface} + +On every supported operating system platform \gpsbabel\ basically is a command line program. This kind of invocation, providing the utmost freedom of including runtime options, creates the best possible flexibility. Unfortunately, that can +sometimes lead to unwieldy command lines. + +To use this program, just tell it +\begin{itemize} +\item what kind of data you want to read, +\item where to read it from, +\item what format you want to be written, +\item and what file or device to write it to. +\end{itemize} + +For example% +\footnote{In our examples we frequently split the respective command lines into several real lines to create a better readability. If a command line ends in a "\bsl " (being the usual continuation character of an input line), this means for actual usage that the command itself extends into the next given line.} + +{\tt \small +\begin{tabbing} +gpsbabel~\= -i geo ... \kill +gpsbabel \> -i geo -f /tmp/infile.loc \+ \bsl \\ + -o gpx -F outfile.gpx +\end{tabbing} +} + +tells it to read the file ~{\tt infile.loc}~ in the ~{\tt /tmp}~ directory% +\footnote{Directory delimiters are always given in the Unix-ish variant, i.e.: "/" is used where Windows users would enter a "\bsl" or similar.} in the {\sc geocaching.com} format and create a new file named ~{\tt outfile.gpx}~ in GPX format, to be placed in the present working directory. + +The next command will read waypoint data from a Magellan unit attached to the first +serial port and write them as a geocaching loc file. The first command is the Linux variant, the second command does the same for windows. + +{\tt \small +gpsbabel -i magellan -f /dev/ttyS0 -o geo -F mag.loc + +gpsbabel -i magellan -f com1 -o geo -F mag.loc +} + +\bigskip + +{\tt \small gpsbabel -?} will always show you the supported file types. + +\bigskip + +People less familiar with the command line will find a GUI interface helpful. A first one, for Windows, is described in section~\ref{GUI}. + + + +\section{Modes of operation: waypoints, routes, tracks} + +There are three basic entities of GPS data that are of interest for a general conversion utility: waypoints, routes, and tracks. + +\begin{description} + +\item[Waypoints] describe isolated and unrelated points in space each. Each is specified by its position (latitude, longitude, height above sea level), a "short" name (that is usually displayed to describe it on the receiver), a comment (or "long" name; an extended text associated to the waypoint), an icon (to display it on a receiver's map display page), and several less important featurs (like time of creation, display options, ...) that even vary between the different receivers.\\ +Transferring waypoints is \gpsbabel 's {\bfseries default mode of operation}. It may as well be invoked by entering a {\tt -w} as {\em first} command line argument.\\ +Optionally, you may specify {\tt -s} as a command line switch. This causes the program to ignore any "short" names that may be present in the source data format and synthesize one from the long name. This is particularly useful if you're writing to a target format that +supports more elaborated short names but the source data was written in a very simple style. I use this for writing data from geocaching.com to my Magellan so my waypoints have "real" names instead of the 'GC1234' ones that are optimized for NMEA-only +receivers. + +\item[Routes] are ordered sets of waypoints that describe a path to follow. Since most contemporary GPS receivers have very limited possible set sizes (typically 30 or 50), but support multiple routes to be administered in parallel, the usual way to handle them is to work on a set of routes at the same time. Read: a set of sets is handled.\\ +Treatment of routes is only implemented for a part of \gpsbabel 's formats. Details are given in the respective section on the various format types. To invoke route treatment, {\bfseries enter {\tt -r} as {\em first} command line argument}. + +\item[Tracks] are lists of waypoints with position and creation time information only. They are sampled in larger quantities when traveling. They are intended to describe the traveled path as exactly as possible (if so desired). Track logging memory of the receivers usually can gather 1000 to 10000 individual points.\\ +Treatment of track data is only implemented for a part of \gpsbabel 's formats. Details are given in the respective section on the various format types. To invoke track treatment, {\bfseries enter {\tt -t} as {\em first} command line argument}. + +\end{description} + + + +\section{Supported input and output formats} + +This section describes the supported file or transmission protocol formats in detail. Please remember that the capabilities of the various receiver types are quite different, so transfers from one receiver to another, or from a general file format to a receiver, might go wrong: you cannot deliver more waypoints, route or track points than the target is able to swallow. This kind of error cannot be handled by \gpsbabel . + + + +\subsection{Tabular overview on formats} + +\begin{tabular}{|l|cc|cc|cc|} +\hline + & \multicolumn{2}{c}{Waypoints} & \multicolumn{2}{c}{Tracks} & \multicolumn{2}{c|}{Routes} \\ +File format & Read & Write & Read & Write & Read & Write\\ +\hline +\hline +Cetus & yes & yes & & & & \\ +CoPilot Flight Planner & yes & yes\footnote{Magnetic declination is not written.} + & & & & \\ +CSV & yes & yes & & & & \\ +Delorme S\&A & yes & yes & & & & \\ +Delorme TopoUSA/XMap Conduit + & yes & yes & & & & \\ +~~~~~(XMap) & & & & & & \\ +Delorme HandHeld & yes & yes & & & & \\ +~~~~~Street Atlas USA (XMapWpt) & & & & & & \\ +Garmin serial & yes & yes & yes & & & \\ +GEO & yes & yes & & & & \\ +Geocaching DB & yes & yes & & & --- & --- \\ +GPSDrive & yes & yes & & & & \\ +GPSman & yes & yes & & & & \\ +GPSPilot & yes & yes & & & & \\ +gpsutil & yes & yes & & & & \\ +GPX & yes & yes & yes & yes & yes & yes \\ +Holux & yes & yes & & & & \\ +Magellan serial & yes & yes & yes & yes & yes & yes \\ +Magellan SD card & yes & yes & yes & yes & yes & yes \\ +Magellan Navigator Companion + & yes & yes & & & & \\ +Mapsend & yes & yes & yes & yes & yes & yes \\ +Mapsource & yes & yes & & & & \\ +Maptech Exchange Format (MXF) + & yes & yes & & & & \\ +Navitrack DNA & yes & yes & & & & \\ +OziExplorer & yes & yes & & & & \\ +PCX5 & yes & yes & & & & \\ +PocketStreets 2002 Pushpin + & yes & yes & & & & \\ +Tiger & yes & yes & & & & \\ +TopoMapPro & yes & yes & & & & \\ +Topo by National Geographic + & yes & yes & & & & \\ +XCSV & yes & yes & & & & \\ +\hline +\end{tabular} + +In this table ``---'' means: not applicable since format will by definition not +support a respective type of data. + + +\subsection{CETUS} + + Cetus GPS (http://www.cetusgps.dk/) is a program for Palm/OS. + Working with Ron Parker and Kjeld Jensen, we can now read and write + files for that program. It hasn't been exhaustively tested, but + has seemed fine on every input and output we've tried. + + + +\subsection{CoPilot Flight Planner for Palm OS} + + This code is mostly intended to convert CoPilot databases into + other formats. I don't think you should use this to write + CoPilot databases, although the code is there, mostly because + GPSBabel doesn't convert magnetic declination values. + + Questions, bug reports, etc, to ptomblin at xcski.com + + + http://xcski.com/~ptomblin/CoPilot/ + http://navaid.com/CoPilot/ + + + +\subsection{Delorme S\&A} + + There are a billion variants of Comma Separated Value data. This + is the one that makes Delorme S\&A Deluxe 9 happy. + + + +\subsection{Delorme TopoUSA/XMap Conduit (XMap)} + + Delorme TopoUSA/XMap Conduit is a CSV variant. It's just like S\&A with the addition of a + completely pointless line at the beginning and end of the file. + This is the format used to hot-sync to XMap from withing TopoUSA. + Done with help of Dan Edwards. + + + +\subsection{Delorme XMapHandHeld Street Atlas USA (XMapWpt)} + + Delorme XMapHandHeld Street Atlas USA is CSV variant. This is the format used by XmapHH SA USA on + (at least) PocketPC O/S. This XMap is not to be confused + with the XMap mentioned above. Contributed to gpsbabel by + Alex Mottram. + +Delorme XMap Handheld .WPT for PocketPC is a bit of a kludge. This +document covers XMap Handheld Street Atlas USA edition. + +XMap on the PocketPC stores it's waypoints in individual .wpt files. +For example, waypoints generated by XMap on the PocketPC are stored +by default in the "My Documents" folder using the sequential names +"XMap1.wpt", "XMap2.wpt", ad nauseum. Needless to say, not very +efficient. + +As writing multiple waypoint files is outside of the scope of gpsbabel, +gpsbabel chooses to write one big file, one waypoint per line. +Extracting lines from this file is left as an exercise for the end user. +A simple perl script to handle this conversion is included at the end +of this README. + +It should also be noted that READING multiple files is indeed possible, +but if you have more than a few points, it can be a task. For example: + +gpsbabel -i xmapwpt -f Xmap1.wpt -f Xmap2.wpt -o mapsend -F mapsend.wpt + +will read the two Xmap .wpt files and write one mapsend file. This +is fine for a small handful of points, but could be quite cumbersome +for folks like me who have 100+ waypoints loaded into XMap. For *nix +folks, something as simple as: + +cat *.wpt > /tmp/foo.wpt +gpsbabel -i xmapwpt -f foo.wpt -o mapsend -F mapsend.wpt + +will do the trick just fine. + +\scriptsize +\begin{verbatim} +############ BEGIN SCRIPT +#!/full/path/to/perl +$INPUTFILE = @ARGV[0]; +$TARGETDIR = @ARGV[1]; +$FILENAME = @ARGV[2]; + +if (! $FILENAME) { + print "Usage: xmap_split.pl INPUT_FILE OUTPUT_DIRECTORY FILENAME_BASE\n"; + print " (i.e. xmapl_split.pl points.wpt /tmp/points GPSB)\n"; + print " (created GPSB0001-GPSBXXXX in /tmp/points/ from points.wpt)\n"; + exit; +} + +open (INFILE, $INPUTFILE) || die "Cannot open $INPUTFILE for read!\n"; + +while () { + $lc++; + $filename = sprintf("%s/Gpsb%04d.wpt", $TARGETDIR, $lc); + + open (OUTFILE, ">$filename") || die "Cannot open $filename for write!\n"; + + print OUTFILE $_; + + close(OUTFILE); +} + +exit; + +########### END SCRIPT +\end{verbatim} +\normalsize + + +\subsection{GARMIN serial} + + Waypoint serial upload and download works reliably under both + POSIX and Windows. I tested it with a Vista graciously provided + on loan by Joe Armstrong. The communications library used, jeeps, + claims to support most models of Garmin hardware. Be sure the GPS + is set for "Garmin mode" in setup and that nothing else (gpsd, getty, + pppd, etc.) is using the serial port. + + + +\subsection{GEO} + + geocaching.com spits up geocaching.loc files that are XML-ish but + not quite GPX. Because it's so close to GPX, this format is very + well supported. + + + +\subsection{Geocaching DB} + + This is a PDA file format. It was tested against version 2 + of GeocachingDB and a development snapshot of version 3. + Information on the file format came from Dougs Brat and Ron Parker. + A particularly handy way to use GPSBabel on these files is to use + GPSBabel to read a GPX file with Groundspeak (geocaching.com) + extensions and let it write you a GeocachingDB file that contains + the cache names, difficulty, terrain, and such. + + http://vip.hyperusa.com/~dougs/geocachingdb/geocachingdb.htm + + + +\subsection{GPSDRIVE} + + GpsDrive way.txt file format. A space seperated format file. Tested + against GpsDrive v 1.30 found @ http://www.kraftvoll.at/software. + Contributed by Alan Curry. + + + +\subsection{GPSMAN} + + GPS Manager can read and write formats that this converter doesn't + understand. The default formats (WGS84, DDD) work reliably. + + + +\subsection{GPSPILOT} + + The file format for GPSPILOT (http://www.gpspilot.com) was provided + by Ron Parker. The output from this module has been tested with + GPSPilot Tracker v5.05sx, but it is based on reverse-engineering + so it may not work with all versions of all GPSPilot products. + It had read-only support for Airport, Navaid, City and Landmark + files but will read and write Point files. + + + +\subsection{GPSUTIL} + + GPSUtil has a simple file format of this program that runs on POSIX- + compliant OSes like UNIX and Linux. Reads and writes of this format + are reliable. (I've also contributed to this program.) It's + available at http://www.cs.uakron.edu/~hennings/gpsutil/. + + + +\subsection{GPX} + + This is the most capable and expressive of all the file formats + supplied. It is described at http://www.topografix.com/gpx.asp + and is supported by EasyGPS, ExpertGPS, and man other programs + described at http://www.topografix.com/gpx\_resources.asp + + + +\subsection{HOLUX} + + The Holuxgm-100 (e-fox) gps receiver uses standard compact + flash cards. File formats were provided by Holux-Taiwan + http://www.holux.com.tw to the author. The code was tested + against version 2.27E1; other versions and receivers may + work but have not been explictly tested. Anyone with + information on other Holux receivers is encouraged to contact + jochen@bauerbahn.net. + + When copying the .wpo file to a flash card, the file must be + named "tempwprt.wpo" as the receiver will ignore all other + files. + + Comparing the waypoints of a .wpo files against other formats + like .gpx you may notice a small difference in the latitude + and longitude values. The reason is the low resolution of + the coordinates in the wpo file format. In a .wpo file the + reolution is 1/10"; in gpx for example it is 1/100". A a practical + matter, this loss is only about 1.7meters (5 feet). + + + The generated waypoint failes can also be used by MapShow + version 1.14. This program is free of charge from the Holux web + site. + + This format was contributed by Jochen Becker. + + + +\subsection{MAGELLAN (serial and SD card formats)} +\label{MagellanSerial} + +\begin{description} + +\item[Description:] This protocol supports serial uploads and downloads for the majority of the Magellan units. It has been tested to work reliably with the 315, 330, Meridian, and SportTrak family. In fact, it should work on any modern Magellan unit.\\ +Since the contents of the serial interface data transfer is the same that is written to or read from SD cards in the Meridian series, this kind of transfer is automatically supported as well.\\ +\gpsbabel\ can also read and write the files that are written to or read from the SD flash memory cards in the Meridian models. Simply specify a file instead of a serial port.\\ +% +{\small As of this writing, there is still a lot of "scribbling" in the +source for functionality that isn't hooked up to the rest of the +program. Communication errors are handled.} + +\item[Applicability:] Waypoints, tracks, routes + +\item[Additional invocation options:]~\\ +{\bfseries baud}: Baud rate settings may be 1200, 2400, 4800, 9600, 19200 for serial line connections and must match receiver settings. Default value is 4800.\\ +{\bfseries noack}: Specifying "noack" turns handshake mode off. Without handshaking transfer of data is sped up significantly but {\em might} lead to overlooked transmission faults. Those have never been experienced during any testing, though. Default setting is "handshake on".\\ +{\bfseries deficon}: It is possible to specify a default icon to be displayed for every transmitted waypoint. Please refer to appendix~\ref{MagellanDefIcons} for a list of those. + +\item[Usage example:] Read waypoint data from a Magellan receiver via the first serial line interface (Linux/Unix nomenclature given; for Windows replace "/dev/ttyS0" by "com1" etc.) with increased speed, but without handshaking, and write it to a Magellan formatted file.\\[-8mm] +{\tt \small +\begin{tabbing} +gpsbabel~\= -i ... \kill +gpsbabel \> -i magellan,noack,baud=9600 -f /dev/ttyS0 \bsl \+ \\ + -o magellan -F outfile.mag +\end{tabbing} +} + +\end{description} + + + + +\subsection{Magellan Navigator Companion (MAGNAV)} + +Magellan NAV Companion for Palm/OS is not really designed for this +sort of use, but its file format is supported and with a little bit +of patience you can both read and write NAV Companion waypoints. + +This conversion is based on partially +incomplete reverse-engineering of the record format, so it may not +work with all versions of NAV Companion. It has been tested with +version 2.10. + +Translating NAV Companion waypoints to another format is as easy +as with any other format. Just find the Companion\_Waypoints database +in your palm backup directory and use it as the input file. + +When translating waypoints back to NAV Companion, though, you need +to jump through some hoops: + +First, you must merge any waypoints that already exist in the database +in your Palm Backup directory with the ones you are adding; failure to +do so will result in only the new points being available in NAV Companion, +even if you give the new database a different name (it will overwrite +the old database, even in your backup directory. That's a feature of +PalmOS, not of NAV Companion.) + +To merge the databases, use a command line like the following: + +gpsbabel -i magnav -f Companion\_Waypoints.PDB -i geo -f geocaching.loc -o magnav -F merged.pdb + +Second, you must use the installer to install your new PDB file. Don't +make the mistake of copying it over the existing Companion\_Waypoints.PDB +file; the one on the handheld will overwrite it rather than merging with +it. + +Finally, because NAV Companion is not designed to work with desktop +applications, you must tell NAV Companion that its waypoints database +has changed out from under it. One way to do this is to go to the +waypoints screen and attempt to scroll; that will force it to reread +the database and fix the record pointers that it keeps on the heap. + + + +\subsection{MAPSEND} + + Magellan was smart enough to document their file format to make + creating software like this possible. + + + +\subsection{MAPSOURCE} + + Garmin Mapsource format appears compatible with the various + members of that product family. Icon mapping is oriented toward + versions above 4.07. Altitude, proximity, and depth are not + supported. + + Information on the Garmin Mapsource format was provided by Ian + Cowley. The code was implemented by Robert Lipe. + + + +\subsection{Maptech Exchange Format (MXF)} + + Maptech Exchange Format - Another CSV format file. This format + complies with (at least) Maptech Terrain Navigator, Terrain + Professional, Take a Hike, and ExpertGPS import/export MFX. + Contributed by Alex Mottram. + + + +\subsection{Navitrak DNA} + + Navitrak DNA marker format - Another CSV format file. + This is the format that is compatible with the DNA Desktop + import/export command. Reading the binary Markers.jwp + format directly off the data card is not supported yet. + Contributed by Tim Zickus. + + + +\subsection{OZI} + + OziExplorer Waypoint Format - Another CSV format file. Tested + against OziExplorer v 3.90.3a / Shareware. Contributed by Alex + Mottram. + + + +\subsection{PCX5} + + Garmin documents only PCX5, an older format limited to the lame NMEA + six-character waypoint names that's treated as a second-class citizien + in current versions of MapSource. Use file->import to read these + files. Anyone with information on the *.mps file format that is + now preferred is encouraged to contact me with the details or better + yet, a module that implements it. I spent time trying to reverse- + engineer a couple of *.mps files then I remembered that I don't own + a Garmin and wasn't that inspired. + + + +\subsection{Pocket Streets Pushpin (PSP)} + + Microsoft's PocketStreets 2002 Pushpin (.PSP) format is not yet + completely documented. THE .PSP MODULE DOES NOT WORK WITH MS + STREETS \& TRIPS 2002 .EST FILES. To create .PSP files from + Streets \& Trips 2002, you will need to have PocketStreets support + installed. Please note that MS Streets \& Trips only *EXPORTS* + .PSP files. It does not import them. MS Streets \& Trips 2002 + only imports CSV files. To use .PSP files, simply copy them + over to the same folder on the mobile device as the map (.MPS), + and open PocketStreets. It should also be noted that in the case + a pushpin is outside of the exported map area, the pin will be + "grayed-out" and unused in PocketStreets. This is a good thing + as it allows us to create one big .PSP file that covers multiple + .MPS files. Unfortunately, you need one .PSP file for every + .MPS file. :( + +Q: Why should I use gpsbabel/psp to make pushpins when Streets \& Trips (S\&T) + already does that for me? + +A: gpsbabel/psp has the advantage of being able to create pushpins WITHOUT + creating the associated map file and the need to "import" the waypoint + data into S\&T. Through a series of scripts, you can create a dozen + or so PSP files in a few seconds as opposed to a few weeks using the + S\&T interface. The maps are not going to change between sessions, + only the pins will. Why waste all that time creating maps when all you + really want are updated pins? As an aside, gpsbabel/psp creates points + WITH THE PROPER coordinates where S\&T does not in some areas of the U.S. + (Nashville, TN for instance). + + +Q: I keep getting a blank (32 byte) PSP file? + +A: There are either no points to write, or you have botched the command + line for gpsbabel. gpsbabel is sensitive to UPPER and lower case + on the command line. A simple command line to create PSP files + looks like this: + + gpsbabel -i geo -f geocaching.loc -o psp -F NewOrleans.psp + + Note the use of "-f" for INPUT files and "-F" for OUTPUT files. + + +Q: I've created a PSP file, now what do I do with it? + +A: To use pushpins in Pocketstreets, you need to have both a map and a + pushpin file. These two files must exist in the same folder and have + exactly the same base name as the map. For example, the pins that + correspond to the map "NewOrleans.mps" should be named "NewOrleans.psp". + + +Q: I don't have a map? What do I do now? + +A: Create one using the "Export map to Pocketstreets" option in S\&T. You + can also pick up some major city maps on the web from the MS Pocketstreets + website if you are interested in seeing how it works. + + +Q: I have .EST files, not .PSP files. What's up with that? + +A: In order to make PSP files, you need to use the "Export map to + Pocketstreets" function in S\&T. .EST files are for use in S\&T, not + Pocketstreets. + + +Q: The .PSP files differ when I use gpsbabel/psp versus Pocketstreets to + create them. What's up? + +A: Pocketstreets makes corrections to the S\&T waypoint data upon initial + loading. gpsbabel/psp writes PSP files with these corrections already made. + Ask MS. + + +Q: Does gpsbabel/psp work with (Autoroute, Mappoint, etc..) .PSP files? + +A: As of this writing, I haven't seen any so I can't be sure. If they + follow the same layout as S\&T 2002, I'd imagine so. + + +Q: Does gpsbabel/psp work with (S\&T 2001, S\&T 2002, etc...) files? + +A: MS the file layout between S\&T 2001 and S\&T 2002. The gpsbabel psp + module is known to work fine with S\&T 2002 and 2003. + + +Q: Does gpsbabel/psp work with (insert your country/location here) maps? + +A: If it doesn't, feel free to email the PSP files to me at: + geo\_alexm at cox-internet.com. I only had USA based data to work + with while figuring out the file layout. Please include as much + information about the points as possible (lat/long, name, etc..) + and do it in English. I don't read or speak any other languages + fluently. + + +Q: What do you mean S\&T writes points with the wrong coordinates? + +A: At some point in the "Export map to Pocketstreets" function in S\&T, + it goofs the lat/long data. Points in Nashville tended to shift + 1.4 miles WEST of their original location. I'm not a geometry buff, + but I'd imagine they have a reference point for generating coordinates + that's wrong in (at least) that area. + + +Q: I have 800 waypoints that cover a dozen or so Pocketstreets maps. + Do I need to to split my points up into smaller chunks to match the + area covered by the maps? + +A: No. Pocketstreets will "ignore" points that are outside of the map + area. Points that are not on the current map will be "grayed out" + in pushpin explorer in Pocketsreets. This is the reason the PSP + module was written for gpsbabel in the first place. + + +Q: Where can I find documentation for the layout of PSP files? + +A: Just about everything I know about the PSP file format is documented + in the source. To the best of my knowledge, there is no documentation + (and for good reason, I've come to discover). + + +Q: I have some other problem, what do I do? + +A: Email me at geo\_alexm at cox-internet.com and I'll see if I can + work it out. + + + +\subsection{TIGER} + + The U.S. Census Bureau proives online mapping facilities. This + format is described at: http://tiger.census.gov/instruct.html. + + + +\subsection{TopoMapPro} + + TopoMapPro Places File. Reads and writes places files for use + in TopoMapPro (http://www.topomappro.com). As this file type + can store links other than web links, anything that is not a + http url will be discarded. Note that this does not do datum + conversions, so if your input file does not have WGS84/NZGD2000 + data, your output file won't either. + Colour of waypoint icons defaults to red. + + + +\subsection{National Geographic Topo! (TPG)} + + National Geographic Topo! Waypoint Format. This filter + reads and writes .TPG files created by various editions of NG Topo! + This filter will *not* work with the newer combined .TPO files. + Contributed by Alex Mottram. + + + +\subsection{XCSV} + +XCSV is an open-ended "Whatever Separated Values" parser / writer +designed to work with user-supplied "style" files. It should handle +at least a few thousand of the billion CSV variants available. +By itself, it doesn't comply to any format, however *most* CSV +variants can be described as a "style" and fine-tuned by the end +user. For more information on it's use, please see README.style +in the style/ sub-directory of gpsbabel. For an example of using +the XCSV module within your C program, look at the ozi.c, mxf.c, and +xmapwpt.c sources in the gpsbabel directory. This module was +contributed to gpsbabel by Alex Mottram. + +Additional Options: +style - **REQUIRED** Path to XCSV style file. + +snlen - Maximum length of synthesized shortnames. +snwhite - Switch defining whether or not to allow whitespace + in synthesized shortnames. + (0 = NO WHITESPACE, 1 = WHITESPACE OK). +snupper - Switch defining whether or not to force uppercase + in shortnames. (0 = LEAVE AS IS, 1 = UPPERCASE ALL). + +NOTE: sn* options require use of the '-s' command line option. + +Example Usage: +{\tt \small +\begin{tabbing} +gpsbabel~\= -i geo -f 1.loc -f 2.loc \kill +gpsbabel \> -i gpsbabel -s -i gpx -f infile.gpx \bsl \+ \\ + -o xcsv,style=my.style,snlen=8 -F outfile +\end{tabbing} +} +{\tt \small +\begin{tabbing} +gpsbabel~\= -i geo -f 1.loc -f 2.loc \kill +gpsbabel \> -i xcsv,style=your.style -f infile \bsl \+ \\ + -o xcsv,style=my.style -F outfile +\end{tabbing} +} + + + + +\section{Format-independent data filtering options} + +\gpsbabel\ supports data filtering. Data filters are invoked from +the command line via the {\tt -x} option. They are invoked in the order they appear on the command +line and can be used intermittently between several variations +of input and output functions. It should also be noted that +filtering data from different input types can sometimes produce +undesirable results due to differences in the native data formats. + + + +\subsection{POSITION} + +The position filter is designed to remove points based on their +proximity to each other. Distances can be passed on the command +line by passing the distance=XXX option to the filter. Distance +options may be expressed in feet (distance=3f) or meters +(distance=1m). The default is zero feet, essentially a duplicate +position. + +For example: +{\tt \small +\begin{tabbing} +gpsbabel~\= -i geo -f 1.loc -f 2.loc \= \kill +gpsbabel \> -i geo -f 1.loc -f 2.loc \> \bsl \+ \\ + -x position,distance=1f \> \bsl \\ + -o mapsend -F 3.wpt +\end{tabbing} +} +would load two input files of the {\sc geo} type, remove multiple points that are within 1~foot of each other, +leaving just one, and finally would save a {\sc mapsend} type output file. + + + +\subsection{RADIUS} + +The radius filter is designed to include points based on their +proximity to a central point. Distances and the central point +are declared on the command line by passing the distance=X.XX, +lat=X.XX, and lon=X.XX options to the filter. Distance options +may be expressed in miles (distance=3M) or kilometers (distance=3K). +The default is zero miles. + +For example: +{\tt \small +\begin{tabbing} +gpsbabel~\= -i geo -f 1.loc -f 2.loc \kill +gpsbabel \> -i geo -f 1.loc \bsl \+ \\ + -x radius,distance=1.5M,lat=30.0,lon=-90.0 \bsl \\ + -o mapsend -F 2.wpt +\end{tabbing} +} +would load a {\sc geo} input file, but include only points that lie within 1.5 miles of N\,30.000 ~W\,90.000~ into the {\sc mapsend} output file. + + + +\subsection{DUPLICATE} + +The duplicate filter is designed to remove duplicate points based +on their shortname (traditionally a waypoint's name on the GPS +receiver), and/or their location (to a precision of 6 decimals). +This filter supports two options, "shortname" and "location". +Generally, at least one of these options is REQUIRED. + +For example: +{\tt \small +\begin{tabbing} +gpsbabel~\= -i geo ... \kill +gpsbabel \> -i gpx -f 1.gpx -f 2.gpx \bsl \+ \\ + -x duplicate,location,shortname \bsl \\ + -o gpx -F merged\_with\_no\_dupes.gpx +\end{tabbing} +} +would remove points that have duplicate shortnames *AND* duplicate +locations. The result would be a GPX file that more than likely +contains only unique points and point data. + + + +\section{GUI wrappers} +\label{GUI} + +gpsbabelfront(.exe) is is a Windows front-end for GPSBabel. It was contributed and is +maintained by Josh McKee. It is written in Delphi. Figure~\ref{babelfrontfig1} shows a screenshot of it. + +\begin{figure}[htb] +\hfil\psfig{figure=babelfront2.eps,width=0.8\textwidth}\hfil +\caption{Screenshot of the Babel frontend.} +\label{babelfrontfig1} +\end{figure} + + + +\section{Power usage} + +Argument are processed in the order they appear on the command line. +{\bfseries Input is cumulative}. The input file type remains unchanged until a +new -i argument is seen. Files are read in the order they appear. +So you could merge three input files into one output file with: +{\tt \small +\begin{tabbing} +gpsbabel~\= -i geo ... \kill +gpsbabel \> -i geo -f in-1.loc -f in-2.loc -f in-3.loc \+ \bsl \\ + -o geo -F big-out.loc +\end{tabbing} +} + +You can as well {\bfseries merge files of different types}: +{\tt \small +\begin{tabbing} +gpsbabel~\= -i geo ... \kill +gpsbabel \> -i geo -f 1.loc \+ \bsl \\ + -i gpx -f 2.gpx \bsl \\ + -i pcx -f 3.pcx \bsl \\ + -o gpsutil -F big-out.gps +\end{tabbing} +} + +You can {\bfseries write} the same data {\bfseries in different output formats}: +{\tt \small +\begin{tabbing} +gpsbabel~\= -i geo ... \kill +gpsbabel \> -i geo -f 1.loc \+ \bsl \\ + -o gpx -F out-1.gpx \bsl \\ + -o pcx -F out-2.wpt +\end{tabbing} +} + + + +\section{Building it from source} + +The source code should be compilable on any system with ISO C89 compilers. +It has been tested on UnixWare, OpenServer, OS/X, Linux, Solaris, and +a variety of further processors and compilers. + +{\sc Libexpat} is required. If you get errors about {\sc expat.h} being +missing, you must either edit the {\sc Makefile} to tell the compiler +where it is or install it in a sensible place. Expat can be +downloaded from http://expat.sourceforge.net. As part of Apache +it is very portable. + + + +\begin{appendix} + + +\section{How to contribute} +\label{HowToContribute} + +If you are interested in contributing to this program, here are some +guidelines: + +\begin{itemize} + +\item The frontier development state can always be obtained from a publicly accessible CVS on Sourceforge: {\sc cvs.gpsbabel.sourceforge.net}. Check this CVS first before beginning your own enhancement efforts. + +\item Please ensure that you are building and testing against the latest code +from the top of the CVS tree and that any code you modify is the latest +version from the CVS. Please remember: Code changes sometimes occur frequently! + +\item Standards are good. ISO C and POSIX are greal preferred. + +\item Reuse is OK, if doing so is not onerous. For example, using the {\sc expat} +libraries vastly simplifies the XML parsers while increasing their +robustness plus those libraries are ubiquitous. So I consider it OK to +require {\sc expat}. + +\item Mail patches to {\bfseries robertlipe$@$usa.net} for consideration and +integration. + +\item If you are creating a new target you should submit patches (use +"cvs diff -uN" to create patches) to the following files: + \begin{itemize} +\item Yourcode.c and/or Yourcode.h - this is the code required to do your + conversions and any support files that your code requires. +\item vecs.c - an updated vecs.c file implementing your conversion code into + GPSBabel. +\item Makefile - an updated Makefile telling the compiler how to build and link + your conversion into GPSBabel +\item README - an excerpt for the README about your conversion and any + idiosyncrasies it may have. +\item testo - an updated script that tests your conversion (this should produce + no output if all is good, see the current testo script for examples) +\item YourOutput - a sample file of code produced by your function (used in testo + and lives in a directory called "reference"). + \end{itemize} + +\item Compilers complain for a reason. Code shouldn't emit warnings. + +\item The entire world doesn't run just {\em $<$enter your favorite OS here$>$}. I've tested the present code on +five different OSes. If you find yourself wanting to insert compiler or +OS specific magic, please resist. We do not want to separate but to integrate. + +\end{itemize} + + +\section{Magellan icon names} +\label{MagellanDefIcons} + +The table shows the list of icon names available on a variety of Magellan receivers. The names may be used to define a default icon that will be displayed after uploading sets of waypoints to a respective receiver (see section~\ref{MagellanSerial}). + +... + + +\section{Acknowledgements and contact addresses} + + + +\section{Gnu general public license} +\label{GPL} + +... + +\end{appendix} +%============================================================ +%\newpage +%\bibliographystyle{galphac} +%\bibliography{antrag} + +\end{document} + + + + + + + + + + + + + diff --git a/duplicate.c b/duplicate.c new file mode 100644 index 000000000..321834754 --- /dev/null +++ b/duplicate.c @@ -0,0 +1,269 @@ +/* + exact duplicate point filter utility. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include +#include "defs.h" + +extern queue waypt_head; + +static char *snopt = NULL; +static char *lcopt = NULL; +static char *purge_duplicates = NULL; +static char *correct_coords = NULL; + +static +arglist_t dup_args[] = { + {"shortname", &snopt, "Suppress duplicate waypoints based on name", + NULL, ARGTYPE_BOOL}, + {"location", &lcopt, "Suppress duplicate waypoint based on coords", + NULL, ARGTYPE_BOOL}, + {"all", &purge_duplicates, "Suppress all instances of duplicates", + NULL, ARGTYPE_BOOL}, + {"correct", &correct_coords, "Use coords from duplicate points", + NULL, ARGTYPE_BOOL}, + {0, 0, 0, 0, 0} +}; + + +typedef struct btree_node { + struct btree_node *left, *right; + unsigned long data; + waypoint *wpt; +} btree_node; + +static btree_node * +addnode (btree_node * tree, btree_node * newnode, btree_node **oldnode) +{ + btree_node * tmp, * last = NULL; + + if ( *oldnode ) {*oldnode = NULL;} + + if (!tree) + return (newnode); + + tmp = tree; + + while (tmp) { + last = tmp; + if (newnode->data < tmp->data) { + tmp = tmp->right; + } else if (newnode->data > tmp->data) { + tmp = tmp->left; + } else { + if ( oldnode ) { + *oldnode = tmp; + } + return (NULL); + } + } + + if (newnode->data < last->data) { + last->right = newnode; + } else { + last->left = newnode; + } + + return (tree); +} + +void +free_tree (btree_node *tree) +{ + if ( tree->left ) { + free_tree(tree->left); + } + if ( tree->right ) { + free_tree(tree->right); + } + xfree(tree); +} + +typedef struct { + waypoint *wpt; + int index; +} wpt_ptr; + +/* + +It looks odd that we have different comparisons for date and index. + If exported if a < b return 1 + if index if a < b return -1 + +The reason is that we want to sort in reverse order by date, but forward +order by index. So if we have four records: + + date index + June 24 0 + June 25 1 + June 25 2 + June 24 3 + +we want to sort them like this: + + date index + June 25 1 + June 25 2 + June 24 0 + June 24 3 + +Thus, the first point we come across is the latest point, but if we +have two points with the same export date/time, we will first see the +one with the smaller index (i.e. the first of those two points that we +came across while importing waypoints.) + +In the (common) case that we have no exported dates, the dates will all +be zero so the sort will end up being an expensive no-op (expensive +because, sadly, quicksort can be O(n^2) on presorted elements.) +*/ + + +static +int +compare(const void *a, const void *b) +{ + const wpt_ptr *wa = (wpt_ptr *)a; + const wpt_ptr *wb = (wpt_ptr *)b; + + if ( wa->wpt->gc_data.exported < wb->wpt->gc_data.exported ) { + return 1; + } else if ( wa->wpt->gc_data.exported > wb->wpt->gc_data.exported ) { + return -1; + } + + /* If the exported dates are the same, sort by index. */ + if ( wa->index < wb->index ) { + return -1; + } else if (wa->index > wb->index ) { + return 1; + } + + /* If index and date are the same, it's the same element. */ + return 0; + +} + +void +duplicate_process(void) +{ + waypoint * waypointp; + btree_node * newnode, * btmp, * sup_tree = NULL; + btree_node * oldnode = NULL; + unsigned long crc = 0; + struct { char shortname[32]; char lat[13]; char lon[13]; } dupe; + waypoint * delwpt = NULL; + + int i, ct = waypt_count(); + wpt_ptr *htable, *bh; + queue *elem, *tmp; + extern queue waypt_head; + + htable = (wpt_ptr *) xmalloc(ct * sizeof(*htable)); + bh = htable; + + i = 0; + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + bh->wpt = (waypoint *) elem; + bh->index = i; + i ++; + bh ++; + } + qsort(htable, ct, sizeof(*htable), compare); + + for (i=0;ishortname, sizeof(dupe.shortname) - 1); + } + + if (lcopt) { + /* let sprintf take care of rounding */ + sprintf(dupe.lat, "%11.4f", waypointp->latitude); + sprintf(dupe.lon, "%11.4f", waypointp->longitude); + /* The degrees2ddmm stuff is a feeble attempt to + * get everything rounded the same way in a precision + * that's "close enough" for determining duplicates. + */ + sprintf(dupe.lat, "%11.3f", degrees2ddmm(waypointp->latitude)); + sprintf(dupe.lon, "%11.3f", degrees2ddmm(waypointp->longitude)); + + } + + crc = get_crc32(&dupe, sizeof(dupe)); + + newnode = (btree_node *)xcalloc(sizeof(btree_node), 1); + newnode->data = crc; + newnode->wpt = waypointp; + + btmp = addnode(sup_tree, newnode, &oldnode ); + + if (btmp == NULL) { + if ( delwpt ) { + waypt_free(delwpt); + } + if ( correct_coords && oldnode && oldnode->wpt ) { + oldnode->wpt->latitude = waypointp->latitude; + oldnode->wpt->longitude = waypointp->longitude; + } + delwpt = waypointp; + waypt_del(waypointp); /* collision */ + xfree(newnode); + if ( purge_duplicates && oldnode ) { + if ( oldnode->wpt ) { + waypt_del( oldnode->wpt ); + waypt_free( oldnode->wpt ); + oldnode->wpt = NULL; + } + } + + } else { + sup_tree = btmp; + } + } + + if ( delwpt ) { + waypt_free(delwpt); + } + + xfree(htable); + if ( sup_tree ) { + free_tree(sup_tree); + } +} + +void +duplicate_init(const char *args) +{ +} + +void +duplicate_deinit(void) +{ +} + +filter_vecs_t duplicate_vecs = { + duplicate_init, + duplicate_process, + duplicate_deinit, + NULL, + dup_args +}; diff --git a/easygps.c b/easygps.c new file mode 100644 index 000000000..827d2057f --- /dev/null +++ b/easygps.c @@ -0,0 +1,274 @@ +/* + Access to EasyGPS files. + + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA +*/ + + +#include "defs.h" +#include + +static FILE *file_in; +static FILE *file_out; +static void *mkshort_handle; +static char *deficon = NULL; + +#define MYNAME "EasyGPS" + +static +arglist_t easygps_args[] = { +/* {"deficon", &deficon, "Default icon name", "Waypoint", + ARGTYPE_STRING}, */ + {0, 0, 0, 0 } +}; + +static void +rd_init(const char *fname) +{ + char ibuf[100] = {'0'} ; + const char *ezsig = "TerraByte Location File"; + + file_in = xfopen(fname, "rb", MYNAME); + + fread(ibuf, 52, 1, file_in); + + if (strncmp(ibuf, ezsig, sizeof(ezsig)-1) || + ibuf[51] != 'W') { + fatal(MYNAME ": %s is not an EasyGPS file\n", fname); + } +} + +static void +rd_deinit(void) +{ + fclose(file_in); +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "wb", MYNAME); + mkshort_handle = mkshort_new_handle(); +} + +static void +wr_deinit(void) +{ + fclose(file_out); + mkshort_del_handle(mkshort_handle); +} + +/* + * Read a pascal string from file_in and return a copy in allocated + * storage. + */ +static void * +pread(void) +{ + char *d; + int ilen; + + ilen = fgetc(file_in); + d = (char *) xmalloc(ilen + 1); + fread(d, ilen, 1, file_in); + d[ilen] = 0; + return d; +} + +static void +data_read(void) +{ + char p; + char ibuf[10]; + char bbuf[4096]; + char *bbufp; + double d; + do { + unsigned char tag; + waypoint *wpt_tmp; + + wpt_tmp = waypt_new(); + + for (tag = fgetc(file_in); tag != 0xff; tag = fgetc(file_in)) { + switch (tag) { + case 1: + wpt_tmp->shortname = (char *) pread(); + break; + case 2: + case 3: + wpt_tmp->description = (char *) pread(); + break; + case 5: + wpt_tmp->notes = (char *) pread(); + break; + case 6: + wpt_tmp->url_link_text = (char *) pread(); + break; + case 7: + wpt_tmp->icon_descr = (char *) pread(); + break; + case 8: /* NULL Terminated (vs. pascal) descr */ + bbufp = bbuf; + for(;;) { + p = fgetc(file_in); + *bbufp++ = p; + if ( 0 == p ) { + break; + } + } + wpt_tmp->notes = xstrdup(bbuf); + break; + case 9: /* NULL Terminated (vs. pascal) link */ + bbufp = bbuf; + for(;;) { + p = fgetc(file_in); + *bbufp++ = p; + if ( 0 == p ) { + break; + } + } + wpt_tmp->url = xstrdup(bbuf); + break; + case 0x10: + bbufp = bbuf; + for(;;) { + p = fgetc(file_in); + *bbufp++ = p; + if ( 0 == p ) { + break; + } + } + wpt_tmp->url_link_text = xstrdup(bbuf); + break; + case 0x63: + fread(ibuf, 8, 1, file_in); + le_read64(&d, ibuf); + wpt_tmp->latitude = d; + break; + case 0x64: + fread(ibuf, 8, 1, file_in); + le_read64(&d, ibuf); + wpt_tmp->longitude = d; + break; + case 0x65: + case 0x66: + fread(ibuf, 8, 1, file_in); + break; + case 0x84: + case 0x85: + fread(ibuf, 4, 1, file_in); + break; + case 0x86: /* May be proximity. I think it's time. */ + fread(ibuf, 4, 1, file_in); + break; + default: + printf("Unknown tag %x\n", tag); + ; + } + } + waypt_add(wpt_tmp); + p = fgetc(file_in); + } while (!feof(file_in) && (p == 'W')); +} + + + + /* + * Write a Pascal string to the output stream. + */ +static void +write_pstring(const char *p) +{ + int len = strlen(p); + if (len > 255) { + fatal(MYNAME ": String too long at %d bytes\n", len); + } + fputc(len, file_out); + fwrite(p, len, 1, file_out); +} + +static void +ez_disp(const waypoint *wpt) +{ + char tbuf[8]; + fprintf(file_out, "W"); + if (wpt->shortname) { + fputc(1, file_out); + write_pstring(wpt->shortname); + } + if (wpt->description) { + fputc(3, file_out); + write_pstring(wpt->description); + } + if (wpt->icon_descr) { + fputc(7, file_out); + write_pstring(wpt->icon_descr); + } + fputc(0x63, file_out); + le_read64(tbuf, &wpt->latitude); + fwrite(tbuf, 8, 1, file_out); + fputc(0x64, file_out); + le_read64(tbuf, &wpt->longitude); + fwrite(tbuf, 8, 1, file_out); + if (wpt->notes) { + fputc(5, file_out); + write_pstring(wpt->notes); + } + if (wpt->url_link_text) { + fputc(6, file_out); + write_pstring(wpt->url_link_text); + } + if (1 && wpt->url) { + fputc(9, file_out); + fputs(wpt->url, file_out); + fputc(0, file_out); + } + fputc(0xff, file_out); +} + +static void +data_write(void) +{ + setshort_length(mkshort_handle, 6); + + fprintf(file_out, + "TerraByte Location File Copyright 2001 TopoGrafix\n"); + /* + * I don't know what this is. + */ + fprintf(file_out, "%c", 0xb); + + waypt_disp_all(ez_disp); + + /* + * Files seem to always end in a zero. + */ + fputc(0x00, file_out); +} + + +ff_vecs_t easygps_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL, + easygps_args +}; diff --git a/filter_vecs.c b/filter_vecs.c new file mode 100644 index 000000000..f81c545b7 --- /dev/null +++ b/filter_vecs.c @@ -0,0 +1,220 @@ +/* + Describe vectors containing filter operations. + + Copyright (C) 2002,2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include "defs.h" + +typedef struct { + filter_vecs_t *vec; + const char *name; + const char *desc; +} fl_vecs_t; + +extern filter_vecs_t position_vecs; +extern filter_vecs_t radius_vecs; +extern filter_vecs_t duplicate_vecs; +extern filter_vecs_t arcdist_vecs; +extern filter_vecs_t polygon_vecs; +extern filter_vecs_t routesimple_vecs; +extern filter_vecs_t reverse_route_vecs; +extern filter_vecs_t sort_vecs; +extern filter_vecs_t stackfilt_vecs; + +static +fl_vecs_t filter_vec_list[] = { + { + &position_vecs, + "position", + "Remove Points Within Distance", + }, + { + &radius_vecs, + "radius", + "Include Only Points Within Radius", + }, + { + &duplicate_vecs, + "duplicate", + "Remove Duplicates", + }, + { + &arcdist_vecs, + "arc", + "Include Only Points Within Distance of Arc", + }, + { + &polygon_vecs, + "polygon", + "Include Only Points Inside Polygon", + }, + { + &routesimple_vecs, + "simplify", + "Simplify routes", + }, + { + &reverse_route_vecs, + "reverse", + "Reverse stops within routes", + }, + { + &sort_vecs, + "sort", + "Rearrange waypoints by resorting", + }, + { + &stackfilt_vecs, + "stack", + "Save and restore waypoint lists" + }, + { + NULL, + NULL, + NULL + } +}; + +filter_vecs_t * +find_filter_vec(char *const vecname, char **opts) +{ + fl_vecs_t *vec = filter_vec_list; + char *v = xstrdup(vecname); + char *svecname = strtok(v, ","); + + while (vec->vec) { + arglist_t *ap; + char *res; + + if (strcmp(svecname, vec->name)) { + vec++; + continue; + } + + res = strchr(vecname, ','); + if (res) { + *opts = res+1; + + if (vec->vec->args) { + for (ap = vec->vec->args; ap->argstring; ap++){ + char *opt = get_option(*opts, + ap->argstring); + if ( opts ) { + *ap->argval = opt; + } + else if ( ap->defaultvalue ) { + *ap->argval = xstrdup( + ap->defaultvalue); + } + else { + *ap->argval = NULL; + } + } + } + } else { + *opts = NULL; + if (vec->vec->args) { + for (ap = vec->vec->args; ap->argstring; ap++){ + if ( ap->defaultvalue ) { + *ap->argval = xstrdup( + ap->defaultvalue); + } + else { + *ap->argval = NULL; + } + } + } + } + + xfree(v); + return vec->vec; + + } + xfree(v); + return NULL; +} + +void +free_filter_vec( filter_vecs_t *fvec ) +{ + arglist_t *ap; + + if ( fvec->args ) { + for ( ap = fvec->args; ap->argstring; ap++) { + if (ap->argval && *ap->argval) xfree(*ap->argval); + } + } +} + +void +exit_filter_vecs( void ) +{ + fl_vecs_t *vec = filter_vec_list; + while ( vec->vec ) { + if ( vec->vec->f_exit ) { + (vec->vec->f_exit)(); + } + vec++; + } +} + + +/* + * Display the available formats in a format that's easy for humans to + * parse for help on available command line options. + */ +void +disp_filter_vecs(void) +{ + fl_vecs_t *vec; + arglist_t *ap; + + for (vec = filter_vec_list; vec->vec; vec++) { + printf(" %-20.20s %-50.50s\n", + vec->name, vec->desc); + for (ap = vec->vec->args; ap && ap->argstring; ap++) { + if ( !(ap->argtype & ARGTYPE_HIDDEN )) + printf(" %-18.18s %-.50s %s\n", + ap->argstring, ap->helpstring, + (ap->argtype&ARGTYPE_REQUIRED)?"(required)":""); + } + } +} + +/* + * Display the available formats in a format that's easy to machine + * parse. Typically invoked by programs like graphical wrappers to + * determine what formats are supported. + */ +void +disp_filters(int version) +{ + fl_vecs_t *vec; + + switch(version) { + case 0: + for (vec = filter_vec_list; vec->vec; vec++) { + printf("%s\t%s\n", vec->name, vec->desc); + } + break; + default: + ; + } +} diff --git a/garmin.c b/garmin.c new file mode 100644 index 000000000..898fc59ac --- /dev/null +++ b/garmin.c @@ -0,0 +1,674 @@ +/* + Jeeps wrapper for Garmin serial protocol. + + Copyright (C) 2002, 2003, 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include +#include "defs.h" +#include "jeeps/gps.h" +#include "garmin_tables.h" + +#define MYNAME "GARMIN" +static const char *portname; +static void *mkshort_handle; +static GPS_PWay *tx_routelist; +static GPS_PWay *cur_tx_routelist_entry; +static GPS_PTrack *tx_tracklist; +static GPS_PTrack *cur_tx_tracklist_entry; +static char *getposn = NULL; +static char *poweroff = NULL; +static char *snlen = NULL; +static char *snwhiteopt = NULL; + +static +arglist_t garmin_args[] = { + { "snlen", &snlen, "Length of generated shortnames", NULL, + ARGTYPE_INT }, + { "snwhite", &snwhiteopt, "(0/1) Allow whitespace synth. shortnames", + NULL, ARGTYPE_BOOL}, + { "get_posn", &getposn, "Return current position as a waypoint", + NULL, ARGTYPE_BOOL}, + { "power_off", &poweroff, "Command unit to power itself down", + NULL, ARGTYPE_BOOL}, + { 0, 0, 0, 0} +}; + +static const char * d103_symbol_from_icon_number(unsigned int n); +static int d103_icon_number_from_symbol(const char *s); + +static void +rw_init(const char *fname) +{ + int short_length; + + if (!mkshort_handle) + mkshort_handle = mkshort_new_handle(); + + if (global_opts.debug_level > 0) { + GPS_Enable_Warning(); + GPS_Enable_User(); + } + if (global_opts.debug_level > 1) { + GPS_Enable_Diagnose(); + } + GPS_Enable_Error(); + + if (poweroff) { + GPS_Command_Off(fname); + return; + } + + if (GPS_Init(fname) < 0) { + fatal(MYNAME ":Can't init %s\n", fname); + } + portname = fname; + + /* + * Grope the unit we're talking to to set setshort_length to + * 20 for the V, + * 10 for Street Pilot, Rhino, 76 + * 6 for the III, 12, emap, and etrex + * Fortunately, getting this "wrong" only results in ugly names + * when we're using the synthesize_shortname path. + */ + short_length = 10; + + switch ( gps_waypt_type ) /* waypoint type as defined by jeeps */ + { + case 100: /* The GARMIN GPS Interface Specification, */ + case 101: /* says these waypoint types use an ident */ + case 102: /* length of 6. Waypoint types 106, 108 */ + case 103: /* and 109 are all variable length */ + case 104: + case 105: + case 107: + case 150: + case 151: + case 152: + case 154: + case 155: + short_length = 6; + break; + case 106: /* Waypoint types with variable ident length */ + case 108: /* Need GPSr id to know the actual length */ + case 109: + switch ( gps_save_id ) + { + case 130: /* Garmin Etrex (yellow) */ + short_length = 6; + break; + case 155: /* Garmin V */ + short_length = 20; + break; + default: + break; + } + break; + default: + break; + + } + /* + * If the user provided a short_length, override the calculated value. + */ + if (snlen) + setshort_length(mkshort_handle, atoi(snlen)); + else + setshort_length(mkshort_handle, short_length); + + if (snwhiteopt) + setshort_whitespace_ok(mkshort_handle, atoi(snwhiteopt)); + + setshort_mustupper(mkshort_handle, 1); + +} + +static void +rw_deinit(void) +{ + if (mkshort_handle) { + mkshort_del_handle(mkshort_handle); + mkshort_handle = NULL; + } +} + +static int +waypt_read_cb(int total_ct, GPS_PWay *way) +{ + static int i; + + if (global_opts.verbose_status) { + i++; + waypt_status_disp(total_ct, i); + } +} + +static void +waypt_read(void) +{ + int i,n; + GPS_PWay *way; + + if (getposn) { + waypoint *wpt = waypt_new(); + wpt->latitude = gps_save_lat; + wpt->longitude = gps_save_lon; + wpt->shortname = xstrdup("Position"); + waypt_add(wpt); + return; + } + + if ((n = GPS_Command_Get_Waypoint(portname, &way, waypt_read_cb)) < 0) { + fatal(MYNAME ":Can't get waypoint from %s\n", portname); + } + + for (i = 0; i < n; i++) { + waypoint *wpt_tmp = waypt_new(); + + wpt_tmp->shortname = xstrdup(way[i]->ident); + wpt_tmp->description = xstrdup(way[i]->cmnt); + rtrim(wpt_tmp->shortname); + rtrim(wpt_tmp->description); + wpt_tmp->longitude = way[i]->lon; + wpt_tmp->latitude = way[i]->lat; + if (gps_waypt_type == 103) { + wpt_tmp->icon_descr = d103_symbol_from_icon_number( + way[i]->smbl); + } else { + wpt_tmp->icon_descr = mps_find_desc_from_icon_number( + way[i]->smbl, PCX); + } + /* + * If a unit doesn't store altitude info (i.e. a D103) + * gpsmem will default the alt to INT_MAX. Other units + * (I can't recall if it was the V (D109) hor the Vista (D108) + * return INT_MAX+1, contrary to the Garmin protocol doc which + * says they should report 1.0e25. So we'll try to trap + * all the cases here. Yes, libjeeps should probably + * do this and not us... + */ + if ((way[i]->alt == (float) (1U<<31)) || + (way[i]->alt == INT_MAX) || + (way[i]->alt == 1.0e25) + ) { + wpt_tmp->altitude = unknown_alt; + } else { + wpt_tmp->altitude = way[i]->alt; + } + + waypt_add(wpt_tmp); + GPS_Way_Del(&way[i]); + } +} + +static +void +track_read(void) +{ + int32 ntracks; + GPS_PTrack *array; + route_head *trk_head = NULL; + int trk_num = 0; + int i; + int trk_seg_num = 1; + char trk_seg_num_buf[10]; + char *trk_name = ""; + + ntracks = GPS_Command_Get_Track(portname, &array); + + if ( ntracks == 0 ) + return; + + for(i = 0; i < ntracks; i++) { + waypoint *wpt; + + /* + * This is probably always in slot zero, but the Garmin + * serial spec says these can appear anywhere. Toss them + * out so we don't treat it as an extraneous trackpoint. + */ + if (array[i]->ishdr) { + trk_name = array[i]->trk_ident; + if (!trk_name) + trk_name = ""; + trk_seg_num = 1; + continue; + } + + + if ((trk_head == NULL) || array[i]->tnew) { + trk_head = route_head_alloc(); + trk_head->rte_num = trk_num; + if (trk_seg_num == 1) { + trk_head->rte_name = xstrdup(trk_name); + } else { + /* name in the form TRACKNAME #n */ + snprintf(trk_seg_num_buf, sizeof(trk_seg_num_buf), "%d", trk_seg_num); + trk_head->rte_name = xmalloc(strlen(trk_name)+strlen(trk_seg_num_buf)+3); + sprintf(trk_head->rte_name, "%s #%s", trk_name, trk_seg_num_buf); + } + trk_seg_num++; + trk_head->rte_num = trk_num; + trk_num++; + track_add_head(trk_head); + } + + wpt = waypt_new(); + + wpt->longitude = array[i]->lon; + wpt->latitude = array[i]->lat; + wpt->altitude = array[i]->alt; + wpt->shortname = xstrdup(array[i]->trk_ident); + wpt->creation_time = array[i]->Time; + + route_add_wpt(trk_head, wpt); + } + + while(--ntracks) { + GPS_Track_Del(&array[ntracks]); + } + xfree(array); +} + +static +void +route_read(void) +{ + int32 nroutepts; + int i; + GPS_PWay *array; + + nroutepts = GPS_Command_Get_Route(portname, &array); + + fprintf(stderr, "Routes %d\n", (int) nroutepts); +#if 1 + for (i = 0; i < nroutepts; i++) { + route_head *rte_head; + waypoint * wpt_tmp; + + if (array[i]->isrte) { + char *csrc = NULL; + /* What a horrible API has libjeeps for making this + * my problem. + */ + switch (array[i]->rte_prot) { + case 201: csrc = array[i]->rte_cmnt; break; + case 202: csrc = array[i]->rte_ident; break; + default: break; + } + rte_head = route_head_alloc(); + route_add_head(rte_head); + if (csrc) { + rte_head->rte_name = xstrdup(csrc); + } + ; + + } else { + if (array[i]->islink) { + continue; + } else { + wpt_tmp = xcalloc(sizeof (*wpt_tmp), 1); + wpt_tmp->latitude = array[i]->lat; + wpt_tmp->longitude = array[i]->lon; + wpt_tmp->shortname = array[i]->ident; + route_add_wpt(rte_head, wpt_tmp); + } + } + } +#else + GPS_Fmt_Print_Route(array, nroutepts, stderr); +#endif + +} + +static void +data_read(void) +{ + if (poweroff) { + return; + } + + if (global_opts.masked_objective & WPTDATAMASK) + waypt_read(); + if (global_opts.masked_objective & TRKDATAMASK) + track_read(); + if (global_opts.masked_objective & RTEDATAMASK) + route_read(); + if (!(global_opts.masked_objective & + (WPTDATAMASK | TRKDATAMASK | RTEDATAMASK))) + fatal(MYNAME ": Nothing to do.\n"); +} + +static GPS_PWay +sane_GPS_Way_New(void) +{ + GPS_PWay way; + way = GPS_Way_New(); + if (!way) { + fatal(MYNAME ":not enough memory\n"); + } + + /* + * Undo less than helpful defaults from Way_New. + */ + way->rte_ident[0] = 0; + way->rte_cmnt[0] = 0; + way->rte_link_subclass[0] = 0; + way->rte_link_ident[0] = 0; + way->city[0] = 0; + way->state[0] = 0; + way->facility[0] = 0; + way->addr[0] = 0; + way->cross_road[0] = 0; + way->cross_road[0] = 0; + way->dpth = 1.0e25; + way->wpt_class = 0; + + return way; +} + +static int +waypt_write_cb(GPS_PWay *way) +{ + static int i; + int n = waypt_count(); + + if (global_opts.verbose_status) { + i++; + waypt_status_disp(n, i); + } + return 0; +} + +static void +waypoint_write(void) +{ + int i; + int32 ret; + int n = waypt_count(); + queue *elem, *tmp; + extern queue waypt_head; + GPS_PWay *way; + extern int32 gps_save_id; + int icon; + + way = xcalloc(n,sizeof(*way)); + + for (i = 0; i < n; i++) { + way[i] = sane_GPS_Way_New(); + } + + i = 0; + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + waypoint *wpt; + char *ident; + char *src = NULL; + char obuf[256]; + + wpt = (waypoint *) elem; + + if(wpt->description) src = wpt->description; + if(wpt->notes) src = wpt->notes; + + ident = global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, src) : + wpt->shortname; + /* Should not be a strcpy as 'ident' isn't really a C string, + * but rather a garmin "fixed length" buffer that's padded + * to the end with spaces. So this is NOT (strlen+1). + */ + memcpy(way[i]->ident, ident, strlen(ident)); + if (global_opts.synthesize_shortnames) { + xfree(ident); + } + way[i]->ident[sizeof(way[i]->ident)-1] = 0; + + if (wpt->gc_data.diff && wpt->gc_data.terr) { + snprintf(obuf, sizeof(obuf), "%d/%d %s", + wpt->gc_data.diff, wpt->gc_data.terr, + src); + memcpy(way[i]->cmnt, obuf, strlen(obuf)); + } else { + memcpy(way[i]->cmnt, src, strlen(src)); + } + way[i]->lon = wpt->longitude; + way[i]->lat = wpt->latitude; + + if (get_cache_icon(wpt)) { + icon = mps_find_icon_number_from_desc(get_cache_icon(wpt), PCX); + } else { + icon = mps_find_icon_number_from_desc(wpt->icon_descr, PCX); + } + + /* For units that support tiny numbers of waypoints, just + * overwrite that and go very literal. + */ + if (gps_waypt_type == 103) { + icon = d103_icon_number_from_symbol(wpt->icon_descr); + } + way[i]->smbl = icon; + if (wpt->altitude == unknown_alt) { + way[i]->alt = 0; + } else { + way[i]->alt = wpt->altitude; + } + i++; + } + + if ((ret = GPS_Command_Send_Waypoint(portname, way, n, waypt_write_cb)) < 0) { + fatal(MYNAME ":communication error sending wayoints..\n"); + } + + for (i = 0; i < n; ++i) { + GPS_Way_Del(&way[i]); + } + if (global_opts.verbose_status) { + fprintf(stdout, "\r\n"); + fflush(stdout); + } + xfree(way); +} + +static void +route_hdr_pr(const route_head *rte) +{ + (*cur_tx_routelist_entry)->rte_num = rte->rte_num; + (*cur_tx_routelist_entry)->isrte = 1; +} + +static void +route_waypt_pr(const waypoint *wpt) +{ + GPS_PWay rte = *cur_tx_routelist_entry; + + /* + * As stupid as this is, libjeeps seems to want an empty + * waypoint between every link in a route that has nothing + * but the 'islink' member set. Rather than "fixing" libjeeps, + * we just double them up (sigh) and do that here. + */ + rte->islink = 1; + cur_tx_routelist_entry++; + rte = *cur_tx_routelist_entry; + + rte->lon = wpt->longitude; + rte->lat = wpt->latitude; + rte->smbl = mps_find_icon_number_from_desc(wpt->icon_descr, PCX); + if (wpt->altitude != unknown_alt) { + rte->alt = wpt->altitude; + } + strncpy(rte->ident, wpt->shortname, sizeof(rte->ident)); + rte->ident[sizeof(rte->ident)-1] = 0; + + if (wpt->description) { + strncpy(rte->cmnt, wpt->description, sizeof(rte->cmnt)); + rte->cmnt[sizeof(rte->ident)-1] = 0; + } else { + rte->cmnt[0] = 0; + } + cur_tx_routelist_entry++; +} + +static void +route_noop(const route_head *wp) +{ +} + +static void +route_write(void) +{ + int i; + int n = 2 * route_waypt_count(); /* Doubled for the islink crap. */ + + tx_routelist = xcalloc(n,sizeof(GPS_PWay)); + cur_tx_routelist_entry = tx_routelist; + + for (i = 0; i < n; i++) { + tx_routelist[i] = sane_GPS_Way_New(); + } + + route_disp_all(route_hdr_pr, route_noop, route_waypt_pr); + GPS_Command_Send_Route(portname, tx_routelist, n); +} + +static void +track_hdr_pr(const route_head *trk_head) +{ + (*cur_tx_tracklist_entry)->tnew = gpsTrue; + (*cur_tx_tracklist_entry)->ishdr = gpsTrue; + if ( trk_head->rte_name ) { + strncpy((*cur_tx_tracklist_entry)->trk_ident, trk_head->rte_name, sizeof((*cur_tx_tracklist_entry)->trk_ident)); + (*cur_tx_tracklist_entry)->trk_ident[sizeof((*cur_tx_tracklist_entry)->trk_ident)-1] = 0; + } + cur_tx_tracklist_entry++; +} + +static void +track_waypt_pr(const waypoint *wpt) +{ + (*cur_tx_tracklist_entry)->lat = wpt->latitude; + (*cur_tx_tracklist_entry)->lon = wpt->longitude; + (*cur_tx_tracklist_entry)->alt = wpt->altitude; + (*cur_tx_tracklist_entry)->Time = wpt->creation_time; + if ( wpt->shortname ) { + strncpy((*cur_tx_tracklist_entry)->trk_ident, wpt->shortname, sizeof((*cur_tx_tracklist_entry)->trk_ident)); + (*cur_tx_tracklist_entry)->trk_ident[sizeof((*cur_tx_tracklist_entry)->trk_ident)-1] = 0; + } + cur_tx_tracklist_entry++; +} + +static void +track_write(void) +{ + int i; + /* Headers plus trackpoints. Trackpoints are added by + * route_add_waypt so get route_waypt_count() + */ + int n = route_waypt_count() + track_count(); + + tx_tracklist = xcalloc(n, sizeof(GPS_PTrack)); + cur_tx_tracklist_entry = tx_tracklist; + + for (i = 0; i < n; i++) { + tx_tracklist[i] = GPS_Track_New(); + } + + track_disp_all(track_hdr_pr, route_noop, track_waypt_pr); + + GPS_Command_Send_Track(portname, tx_tracklist, n); + + for (i = 0; i < n; i++) { + GPS_Track_Del(&tx_tracklist[i]); + } + xfree(tx_tracklist); +} + +static void +data_write() +{ + if (poweroff) { + return; + } + + if (global_opts.masked_objective & WPTDATAMASK) + waypoint_write(); + if (global_opts.masked_objective & RTEDATAMASK) + route_write(); + if (global_opts.masked_objective & TRKDATAMASK) + track_write(); +} + + +ff_vecs_t garmin_vecs = { + ff_type_serial, + rw_init, + rw_init, + rw_deinit, + rw_deinit, + data_read, + data_write, + NULL, + garmin_args +}; + +static const char *d103_icons[16] = { + "dot", + "house", + "gas", + "car", + "fish", + "boat", + "anchor", + "wreck", + "exit", + "skull", + "flag", + "camp", + "circle_x", + "deer", + "1st_aid", + "back-track" +}; + +static const char * +d103_symbol_from_icon_number(unsigned int n) +{ + if (n <= 15) + return d103_icons[n]; + else + return "unknown"; +} + +static int +d103_icon_number_from_symbol(const char *s) +{ + int i; + + if (NULL == s) { + return 0; + } + + for (i = 0; i < sizeof(d103_icons) / sizeof(d103_icons[0]); i++) { + if (0 == case_ignore_strcmp(s, d103_icons[i])) + return i; + } + return 0; +} diff --git a/garmin_tables.c b/garmin_tables.c new file mode 100644 index 000000000..f7bd4ff24 --- /dev/null +++ b/garmin_tables.c @@ -0,0 +1,217 @@ +/* + Garmin icon tables + Based on information provided by Ian Cowley, Sigurd Humerfelt, + and Garmin MapSource + + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + */ + +#include "garmin_tables.h" +#include + +/* MapSource 4.13 */ +icon_mapping_t garmin_icon_table[] = { +/* mps pcx desc */ + { 107, 16384, "Airport" }, + { 73, 8204, "Amusement Park" }, + { 55, 169, "Ball Park" }, + { 6, 6, "Bank" }, + { 13, 13, "Bar" }, + { 104, 8244, "Beach" }, + { 1, 1, "Bell" }, + { 37, 150, "Boat Ramp" }, + { 74, 8205, "Bowling" }, + { 93, 8233, "Bridge" }, + { 94, 8234, "Building" }, + { 38, 151, "Campground" }, + { 56, 170, "Car" }, + { 75, 8206, "Car Rental" }, + { 76, 8207, "Car Repair" }, + { 95, 8235, "Cemetery" }, + { 96, 8236, "Church" }, + { 65, 179, "Circle with X" }, + { 72, 8203, "City (Capitol)" }, + { 71, 8200, "City (Large)" }, + { 70, 8199, "City (Medium)" }, + { 69, 8198, "City (Small)" }, + { 97, 8237, "Civil" }, + { 119, 8262, "Contact, Afro" }, + { 120, 8272, "Contact, Alien" }, + { 121, 8258, "Contact, Ball Cap" }, + { 122, 8259, "Contact, Big Ears" }, + { 123, 8271, "Contact, Biker" }, + { 124, 8273, "Contact, Bug" }, + { 125, 8274, "Contact, Cat" }, + { 126, 8275, "Contact, Dog" }, + { 127, 8263, "Contact, Dreadlocks" }, + { 128, 8264, "Contact, Female1" }, + { 129, 8265, "Contact, Female2" }, + { 130, 8266, "Contact, Female3" }, + { 131, 8261, "Contact, Goatee" }, + { 132, 8268, "Contact, Kung-Fu" }, + { 133, 8276, "Contact, Pig" }, + { 134, 8270, "Contact, Pirate" }, + { 135, 8267, "Contact, Ranger" }, + { 136, 8257, "Contact, Smiley" }, + { 137, 8260, "Contact, Spike" }, + { 138, 8269, "Contact, Sumo" }, + { 52, 165, "Controlled Area" }, + { 89, 8220, "Convenience Store" }, + { 98, 8238, "Crossing" }, + { 51, 164, "Dam" }, + { 53, 166, "Danger Area" }, + { 87, 8218, "Department Store" }, + { 4, 4, "Diver Down Flag 1" }, + { 5, 5, "Diver Down Flag 2" }, + { 41, 154, "Drinking Water" }, + { 63, 177, "Exit" }, + { 77, 8208, "Fast Food" }, + { 7, 7, "Fishing Area" }, + { 78, 8209, "Fitness Center" }, + { 64, 178, "Flag" }, + { 105, 8245, "Forest" }, + { 8, 8, "Gas Station" }, + { 117, 8255, "Geocache" }, + { 118, 8256, "Geocache Found" }, + { 99, 8239, "Ghost Town" }, + { 113, 16393, "Glider Area" }, + { 68, 8197, "Golf Course" }, + { 2, 2, "Green Diamond" }, + { 15, 15, "Green Square" }, + { 108, 16388, "Heliport" }, + { 9, 9, "Horn" }, + { 57, 171, "Hunting Area" }, + { 44, 157, "Information" }, + { 100, 8240, "Levee" }, + { 12, 12, "Light" }, + { 90, 8221, "Live Theater" }, + { 59, 173, "Lodging" }, + { 20, 21, "Man Overboard" }, + { 0, 0, "Marina" }, + { 43, 156, "Medical Facility" }, + { 66, 8195, "Mile Marker" }, + { 101, 8241, "Military" }, + { 60, 174, "Mine" }, + { 79, 8210, "Movie Theater" }, + { 80, 8211, "Museum" }, + { 21, 22, "Navaid, Amber" }, + { 22, 23, "Navaid, Black" }, + { 23, 24, "Navaid, Blue" }, + { 24, 25, "Navaid, Green" }, + { 25, 26, "Navaid, Green/Red" }, + { 26, 27, "Navaid, Green/White" }, + { 27, 28, "Navaid, Orange" }, + { 28, 29, "Navaid, Red" }, + { 29, 30, "Navaid, Red/Green" }, + { 30, 31, "Navaid, Red/White" }, + { 31, 32, "Navaid, Violet" }, + { 32, 33, "Navaid, White" }, + { 33, 34, "Navaid, White/Green" }, + { 34, 35, "Navaid, White/Red" }, + { 102, 8242, "Oil Field" }, + { 115, 16395, "Parachute Area" }, + { 46, 159, "Park" }, + { 45, 158, "Parking Area" }, + { 81, 8212, "Pharmacy" }, + { 47, 160, "Picnic Area" }, + { 82, 8213, "Pizza" }, + { 83, 8214, "Post Office" }, + { 109, 16389, "Private Field" }, + { 36, 37, "Radio Beacon" }, + { 3, 3, "Red Diamond" }, + { 16, 16, "Red Square" }, + { 10, 10, "Residence" }, + { 10, 10, "House" }, + { 11, 11, "Restaurant" }, + { 54, 167, "Restricted Area" }, + { 39, 152, "Restroom" }, + { 84, 8215, "RV Park" }, + { 91, 8226, "Scales" }, + { 48, 161, "Scenic Area" }, + { 85, 8216, "School" }, + { 116, 16402, "Seaplane Base" }, + { 19, 19, "Shipwreck" }, + { 58, 172, "Shopping Center" }, + { 112, 16392, "Short Tower" }, + { 40, 153, "Shower" }, + { 49, 162, "Skiing Area" }, + { 14, 14, "Skull and Crossbones" }, + { 110, 16390, "Soft Field" }, + { 86, 8217, "Stadium" }, + { 106, 8246, "Summit" }, + { 50, 163, "Swimming Area" }, + { 111, 16391, "Tall Tower" }, + { 42, 155, "Telephone" }, + { 92, 8227, "Toll Booth" }, + { 67, 8196, "TracBack Point" }, + { 61, 175, "Trail Head" }, + { 62, 176, "Truck Stop" }, + { 103, 8243, "Tunnel" }, + { 114, 16394, "Ultralight Area" }, + { 139, 8282, "Water Hydrant" }, /* new in MapSource V5 */ + { 18, 18, "Waypoint" }, + { 17, 17, "White Buoy" }, + { 35, 36, "White Dot" }, + { 88, 8219, "Zoo" }, + + /* These are experimental and for the custom icons in the new "C" + * models. As of this writing, firmware problems impair their + * general use. + * + * "Quest" supports more icons than this, but other problems + * prohibit us from running with that model, so we stop at 24. + * + * Mapsource doesn't yet know how to do these, so we made the icon + * numbers "-2" to signify that as a problem until we can create + * these in a .mps or .gdb file and see their representation there. + */ + { -2, 7680, "Custom 1" }, + { -2, 7681, "Custom 2" }, + { -2, 7682, "Custom 3" }, + { -2, 7683, "Custom 4" }, + { -2, 7684, "Custom 5" }, + { -2, 7685, "Custom 6" }, + { -2, 7686, "Custom 7" }, + { -2, 7687, "Custom 8" }, + { -2, 7688, "Custom 9" }, + { -2, 7689, "Custom 10" }, + { -2, 7690, "Custom 11" }, + { -2, 7691, "Custom 12" }, + { -2, 7692, "Custom 13" }, + { -2, 7693, "Custom 14" }, + { -2, 7694, "Custom 15" }, + { -2, 7695, "Custom 16" }, + { -2, 7696, "Custom 17" }, + { -2, 7697, "Custom 18" }, + { -2, 7698, "Custom 19" }, + { -2, 7799, "Custom 20" }, + { -2, 7700, "Custom 21" }, + { -2, 7701, "Custom 22" }, + { -2, 7702, "Custom 23" }, + { -2, 7703, "Custom 24" }, + + { 92, 8227, "Micro-Cache" }, /* icon for "Toll Booth" */ + { 48, 161, "Virtual cache" }, /* icon for "Scenic Area" */ + { 86, 8217, "Multi-Cache" }, /* icon for "Stadium" */ + { 44, 157, "Unknown Cache" }, /* icon for "Information" */ + { 64, 178, "Locationless (Reverse) Cache" }, /* Icon for "Flag" */ + { 83, 8214, "Post Office" }, /* Icon for "Post Office" */ + { 47, 160, "Event Cache" }, /* Icon for "Event" */ + { 90, 8221, "Webcam Cache" }, /* Icon for "Live Theatre" */ + + { -1, -1, NULL }, +}; diff --git a/garmin_tables.h b/garmin_tables.h new file mode 100644 index 000000000..9b58383cb --- /dev/null +++ b/garmin_tables.h @@ -0,0 +1,38 @@ +/* + Garmin icon tables + Based on information provided by Ian Cowley, Sigurd Humerfelt, + and Garmin MapSource + + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + */ + +typedef struct icon_mapping { + const int mpssymnum; + const int pcxsymnum; + const char *icon; +} icon_mapping_t; + +typedef enum {MAPSOURCE, PCX, GARMIN_SERIAL} garmin_formats_e; + +extern const +char *mps_find_desc_from_icon_number(const int icon, + garmin_formats_e garmin_format); +extern int +mps_find_icon_number_from_desc(const char *desc, + garmin_formats_e garmin_format); + +extern icon_mapping_t garmin_icon_table[]; diff --git a/gcdb.c b/gcdb.c new file mode 100644 index 000000000..bde86f8ef --- /dev/null +++ b/gcdb.c @@ -0,0 +1,341 @@ +/* + Read and write GeocachingPDB files. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "coldsync/palm.h" +#include "coldsync/pdb.h" + +#define MYNAME "GeocachingDB" +#define MYTYPE 0x44415441 /* DATA */ +#define MYCREATOR 0x42726174 /* Brat */ + +#define MAXRECSZ 500 /* This is overkill as the records seem to be around 100 + bytes a piece, but being conservative and dealing + with realloc issues just doesn't seem worth it. */ + +typedef enum { + RECTYPE_TEXT = 0, + RECTYPE_DATE = 2 +} gcdb_rectype; + +struct dbfld { + char fldname[4]; + pdb_16 fldtype; + pdb_16 fldlen; +}; + +struct dbrec { + pdb_16 nflds; + struct dbfld dbfld[1]; +}; + +static FILE *file_in; +static FILE *file_out; +static const char *out_fname; +struct pdb *opdb; +struct pdb_record *opdb_rec; + +static char *tbuf = NULL; +static char *tbufp = NULL; + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "rb", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "wb", MYNAME); + out_fname = fname; +} + +static void +wr_deinit(void) +{ + fclose(file_out); + if ( tbuf ) + xfree(tbuf); +} + +static void +data_read(void) +{ + struct pdb *pdb; + struct pdb_record *pdb_rec; + + if (NULL == (pdb = pdb_Read(fileno(file_in)))) { + fatal(MYNAME ": pdb_Read failed\n"); + } + + if ((pdb->creator != MYCREATOR) || (pdb->type != MYTYPE)) { + fatal(MYNAME ": Not a GeocachingDB file.\n"); + } + + for(pdb_rec = pdb->rec_index.rec; pdb_rec; pdb_rec=pdb_rec->next) { + waypoint *wpt = waypt_new(); + struct dbrec *rec = (struct dbrec *) pdb_rec->data; + int nflds; + int length; + int type; + int i; + char *recdata; + int lat_dir = 0; + int lat_deg = 0; + float lat_min = 0.0; + int lon_dir = 0; + int lon_deg = 0; + float lon_min = 0.0; + + nflds = be_read16(&rec->nflds); + recdata = (char *) &rec->dbfld[nflds]; + + for (i = 0; i < nflds; i++) { + length = (unsigned short) be_read16(&rec->dbfld[i].fldlen); + type = be_read16(&rec->dbfld[i].fldtype); + + switch(type) { + case RECTYPE_TEXT: /* Text */ + if (!strncmp("gcid", rec->dbfld[i].fldname,4)) { + wpt->shortname = xstrdup(recdata); + } else + if (!strncmp("gcna", rec->dbfld[i].fldname,4)) { + wpt->description = xstrdup(recdata); + } else + if (!strncmp("lat0", rec->dbfld[i].fldname,4)) { + lat_dir = *recdata == 'N' ? 1 : -1; + } else + if (!strncmp("lat1", rec->dbfld[i].fldname,4)) { + lat_deg = atoi(recdata); + } else + if (!strncmp("lat2", rec->dbfld[i].fldname,4)) { + lat_min = atof(recdata); + } + if (!strncmp("lon0", rec->dbfld[i].fldname,4)) { + lon_dir = *recdata == 'E' ? 1 : -1; + } else + if (!strncmp("lon1", rec->dbfld[i].fldname,4)) { + lon_deg = atoi(recdata); + } else + if (!strncmp("lon2", rec->dbfld[i].fldname,4)) { + lon_min = atof(recdata); + } else + if (!strncmp("take", rec->dbfld[i].fldname,4)) { + wpt->notes = xstrappend(wpt->notes, " Took "); + wpt->notes = xstrappend(wpt->notes, recdata); + } else + if (!strncmp("left", rec->dbfld[i].fldname,4)) { + wpt->notes = xstrappend(wpt->notes, " Left "); + wpt->notes = xstrappend(wpt->notes, recdata); + } else + if (!strncmp("diff", rec->dbfld[i].fldname,4)) { + wpt->gc_data.diff = 10 * atof(recdata); + } else + if (!strncmp("terr", rec->dbfld[i].fldname,4)) { + wpt->gc_data.terr = 10 * atof(recdata); + } + break; +#if 0 + /* This really is the date of the find, + * not the cache creation date. + */ + case RECTYPE_DATE: + if (!strncmp("date", rec->dbfld[i].fldname,4)) { + time_t tm; + tm = be_read32(recdata) * 24 * 3600; + tm -= EPOCH_1904; + wpt->creation_time = tm; + warning( "date %d\n", tm); + } + break; +#endif + } + recdata += (length + 1) & (~1); + } + wpt->latitude = lat_dir * (lat_deg + lat_min/60); + wpt->longitude = lon_dir * (lon_deg + lon_min/60); + waypt_add(wpt); + } + + free_pdb(pdb); +} + + +static int +gcdb_add_to_rec(struct dbrec *rec, char *fldname, gcdb_rectype rectype, void *data) +{ + int length; + static int rec_cnt; + + if (!tbuf) { + tbuf = xcalloc(MAXRECSZ, 1); + tbufp = tbuf; + } + + if (fldname == NULL) { + length = tbufp - tbuf; + be_write16(&rec->nflds, rec_cnt); + memcpy(&rec->dbfld[rec_cnt],tbuf, length); + tbufp = tbuf; + length += 4 + sizeof(struct dbfld) * rec_cnt; + rec_cnt = 0; + return length; + } + + be_write16(&rec->dbfld[rec_cnt].fldtype,rectype); + strncpy(rec->dbfld[rec_cnt].fldname, fldname, 4); + + switch (rectype) { + case RECTYPE_TEXT: + length = 1 + strlen(data); + be_write16(&rec->dbfld[rec_cnt].fldlen, length); + strcpy(tbufp, data); + tbufp += (length + 1) & (~1); + break; + case RECTYPE_DATE: + length = 4; + be_write16(&rec->dbfld[rec_cnt].fldlen, length); + be_write32(tbufp, ((time_t)data - EPOCH_1904)/ (3600 * 24)); + tbufp += length; + break; + default: + abort(); + } + rec_cnt++; + + return length; +} + +static void +gcdb_write_wpt(const waypoint *wpt) +{ + struct dbrec *rec; + static int ct; + int reclen; + char tbuf[100]; + + /* + * We don't really know how many fields we'll have or how long + * they'll be so we'll just lazily create a huge place to hold them. + */ + rec = xcalloc(sizeof(*rec) + 500, 1); + + gcdb_add_to_rec(rec, "gcna", RECTYPE_TEXT, wpt->description); + gcdb_add_to_rec(rec, "gcid", RECTYPE_TEXT, wpt->shortname); + + gcdb_add_to_rec(rec, "lat0", RECTYPE_TEXT, + wpt->latitude < 0 ? "S" : "N"); + + sprintf(tbuf, "%d", (int) wpt->latitude); + gcdb_add_to_rec(rec, "lat1", RECTYPE_TEXT, tbuf); + + sprintf(tbuf, "%f", 60 * (wpt->latitude - + (int) wpt->latitude)); + gcdb_add_to_rec(rec, "lat2", RECTYPE_TEXT, tbuf); + + + gcdb_add_to_rec(rec, "lon0", RECTYPE_TEXT, + wpt->longitude < 0 ? "W" : "E"); + + sprintf(tbuf, "%d", (int) wpt->longitude); + gcdb_add_to_rec(rec, "lon1", RECTYPE_TEXT, tbuf); + + sprintf(tbuf, "%f", 60 * (wpt->longitude - + (int) wpt->longitude)); + gcdb_add_to_rec(rec, "lon2", RECTYPE_TEXT, tbuf); + + if (wpt->gc_data.diff) { + sprintf(tbuf, "%f", wpt->gc_data.diff / 10.0); + gcdb_add_to_rec(rec, "diff", RECTYPE_TEXT, tbuf); + } + + if (wpt->gc_data.terr) { + sprintf(tbuf, "%f", wpt->gc_data.terr / 10.0); + gcdb_add_to_rec(rec, "terr", RECTYPE_TEXT, tbuf); + } + +#if 0 + /* This really is the date of the find, + * not the cache creation date. + */ + if (wpt->creation_time) { + gcdb_add_to_rec(rec, "date", RECTYPE_DATE, (void *) wpt->creation_time); + } +#endif + + /* + * We're done. Build the record. + */ + reclen = gcdb_add_to_rec(rec, NULL, 0, NULL); + + opdb_rec = new_Record(0, 2, ct++, reclen, (const ubyte *)rec); + + if (opdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create record\n"); + } + + if (pdb_AppendRecord(opdb, opdb_rec)) { + fatal(MYNAME ": libpdb couldn't append record\n"); + } + + xfree(rec); +} + +static void +data_write(void) +{ + + if (NULL == (opdb = new_pdb())) { + fatal (MYNAME ": new_pdb failed\n"); + } + + strncpy(opdb->name, out_fname, PDB_DBNAMELEN); + strncpy(opdb->name, "GeocachingDB", PDB_DBNAMELEN); + opdb->name[PDB_DBNAMELEN-1] = 0; + opdb->attributes = PDB_ATTR_BACKUP; + opdb->ctime = opdb->mtime = current_time() + 2082844800U; + opdb->type = MYTYPE; /* CWpt */ + opdb->creator = MYCREATOR; /* cGPS */ + opdb->version = 1; + + waypt_disp_all(gcdb_write_wpt); + + pdb_Write(opdb, fileno(file_out)); +} + + +ff_vecs_t gcdb_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL +}; diff --git a/geo.c b/geo.c new file mode 100644 index 000000000..9e8eeca10 --- /dev/null +++ b/geo.c @@ -0,0 +1,298 @@ +/* + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include "defs.h" +#if !NO_EXPAT +#include +static XML_Parser psr; +#endif + +static int in_wpt; +static int in_name; +static int in_link; +static int in_type; +static int in_cdata; +static char *cdatastr; +static char *typestr; +static char *deficon = NULL; + +static waypoint *wpt_tmp; + +FILE *fd; +FILE *ofd; + +static +arglist_t geo_args[] = { + {"deficon", &deficon, "Default icon name", NULL, ARGTYPE_STRING }, + {0, 0, 0, 0, 0} +}; + +#define MYNAME "geo" +#define MY_CBUF 4096 + +#if NO_EXPAT +void +geo_rd_init(const char *fname) +{ + fatal(MYNAME ": This build excluded GEO support because expat was not installed.\n"); +} + +void +geo_read(void) +{ +} +#else +static void +tag_coord(const char **attrv) +{ + const char **avp = &attrv[0]; + + + while (*avp) { + if (strcmp(avp[0], "lat") == 0) { + sscanf(avp[1], "%lf", + &wpt_tmp->latitude); + } + else if (strcmp(avp[0], "lon") == 0) { + sscanf(avp[1], "%lf", + &wpt_tmp->longitude); + } + avp+=2; + } +} + +static void +tag_name(const char **attrv) +{ + const char **avp = &attrv[0]; + while (*avp) { + if (strcmp(avp[0], "id") == 0) { + wpt_tmp->shortname = xstrdup(avp[1]); + } + avp+=2; + } +} + +static void +tag_type(const char **attrv) +{ + const char **avp = &attrv[0]; + while (*avp) { + if (strcmp(avp[0], "type") == 0) { + wpt_tmp->icon_descr = xstrdup(avp[1]); + } + avp+=2; + } +} + +static void +tag_link(const char **attrv) +{ + const char **avp = &attrv[0]; + while (*avp) { + if (strcmp(avp[0], "text") == 0) { + wpt_tmp->url_link_text = xstrdup(avp[1]); + } + avp+=2; + } +} + +static void +geo_start(void *data, const char *el, const char **attr) +{ + + if (in_wpt) { + if (strcmp(el, "ele") == 0) { + wpt_tmp->altitude = atoi(attr[1]); + } + else if (strcmp(el, "name") == 0) { + tag_name(attr); + } + else if (strcmp(el, "coord") == 0) { + tag_coord(attr); + } + else if (strcmp(el, "type") == 0) { + tag_type(attr); + } + } + + if (strcmp(el, "waypoint") == 0) { + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + in_wpt++; + } else if (strcmp(el, "name") == 0) { + in_name++; + } else if (strcmp(el, "type") == 0) { + tag_type(attr); + in_type++; + } else if (strcmp(el, "link") == 0) { + tag_link(attr); + in_link++; + } +} + +static void +geo_end(void *data, const char *el) +{ + if (in_cdata) { + if (in_name) { + wpt_tmp->description = xstrdup(cdatastr); + } + if (in_link) { + wpt_tmp->url = xstrdup(cdatastr); + } + in_cdata--; + memset(cdatastr,0, MY_CBUF); + } + if (strcmp(el, "waypoint") == 0) { + waypt_add(wpt_tmp); + in_wpt--; + } + else if (strcmp(el, "name") == 0) { + in_name--; + } + else if (strcmp(el, "type") == 0) { + wpt_tmp->icon_descr_is_dynamic = 1; + wpt_tmp->icon_descr = xstrdup(typestr); + memset(typestr,0, MY_CBUF); + in_type--; + } + else if (strcmp(el, "link") == 0) { + in_link--; + } +} + +static void +geo_cdata(void *dta, const XML_Char *s, int len) +{ + char *estr; + if (in_name || in_link) { + estr = cdatastr + strlen(cdatastr); + memcpy(estr, s, len); + in_cdata++; + } + if (in_type) { + estr = typestr + strlen(typestr); + memcpy(estr, s, len); + } +} + +void +geo_rd_init(const char *fname) +{ + fd = xfopen(fname, "r", MYNAME); + + psr = XML_ParserCreate(NULL); + if (!psr) { + fatal(MYNAME ":Cannot create XML parser\n"); + } + + XML_SetElementHandler(psr, geo_start, geo_end); + cdatastr = xcalloc(MY_CBUF,1); + typestr = xcalloc(MY_CBUF,1); + XML_SetCharacterDataHandler(psr, geo_cdata); +} + +void +geo_read(void) +{ + int len; + char buf[MY_CBUF]; + + while ((len = fread(buf, 1, sizeof(buf), fd))) { + if (!XML_Parse(psr, buf, len, feof(fd))) { + fatal(MYNAME ":Parse error at %d: %s\n", + XML_GetCurrentLineNumber(psr), + XML_ErrorString(XML_GetErrorCode(psr))); + } + } + + XML_ParserFree(psr); +} + +#endif + +void +geo_rd_deinit(void) +{ + if ( cdatastr ) { + xfree(cdatastr); + } + if ( typestr ) { + xfree(typestr); + } + fclose(fd); +} + +void +geo_wr_init(const char *fname) +{ + ofd = xfopen(fname, "w", MYNAME); +} + +void +geo_wr_deinit(void) +{ + fclose(ofd); +} + +static void +geo_waypt_pr(const waypoint *waypointp) +{ + char *tmp; + + fprintf(ofd, "\n"); + fprintf(ofd, "", waypointp->shortname); + fprintf(ofd, "", waypointp->description); + fprintf(ofd, "\n"); + + fprintf(ofd, "", + waypointp->latitude, + waypointp->longitude); + fprintf(ofd, "\n"); + + if (waypointp->icon_descr) { + fprintf(ofd, "%s\n", deficon ? deficon : waypointp->icon_descr); + } + if (waypointp->url) { + tmp = xml_entitize(waypointp->url); + fprintf(ofd, "%s\n", + tmp); + xfree(tmp); + } + fprintf(ofd, "\n"); +} + +void +geo_write(void) +{ + fprintf(ofd, "\n"); + waypt_disp_all(geo_waypt_pr); + fprintf(ofd, "\n"); +} + +ff_vecs_t geo_vecs = { + ff_type_file, + geo_rd_init, + geo_wr_init, + geo_rd_deinit, + geo_wr_deinit, + geo_read, + geo_write, + NULL, + geo_args +}; diff --git a/geocaching.loc b/geocaching.loc new file mode 100644 index 000000000..4073f2c98 --- /dev/null +++ b/geocaching.loc @@ -0,0 +1 @@ +geocachehttp://www.geocaching.com/seek/cache_details.asp?ID=3771geocachehttp://www.geocaching.com/seek/cache_details.asp?ID=6711geocachehttp://www.geocaching.com/seek/cache_details.asp?ID=7211geocachehttp://www.geocaching.com/seek/cache_details.asp?ID=9641geocachehttp://www.geocaching.com/seek/cache_details.asp?ID=10019geocachehttp://www.geocaching.com/seek/cache_details.asp?ID=11121geocachehttp://www.geocaching.com/seek/cache_details.asp?ID=12447geocachehttp://www.geocaching.com/seek/cache_details.asp?ID=12666geocachehttp://www.geocaching.com/seek/cache_details.asp?ID=12669 \ No newline at end of file diff --git a/geoniche.c b/geoniche.c new file mode 100644 index 000000000..60f955c70 --- /dev/null +++ b/geoniche.c @@ -0,0 +1,537 @@ +/* + Read and write GeoNiche files. + + Copyright (C) 2003 Rick Richardson + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "coldsync/palm.h" +#include "coldsync/pdb.h" + +#define MYNAME "Geoniche" +#define MYTYPE 0x50454e44 /* PEND */ +#define MYCREATOR 0x47656f4e /* GeoN */ + +static FILE *FileIn; +static FILE *FileOut; +static const char *FilenameOut; +static struct pdb *PdbOut; + +static char Rec0Magic[] = "68000NV4Q2"; + +static char *Arg_dbname = NULL; +static char *Arg_category = NULL; + +static +arglist_t Args[] = { + {"dbname", &Arg_dbname, + "Database name (filename)", NULL, ARGTYPE_STRING }, + {"category", &Arg_category, + "Category name (Cache)", NULL, ARGTYPE_STRING }, + {0, 0, 0, 0 } +}; + +#define ARG_FREE(X) do { if (X) { xfree(X); X = NULL; } } while (0) + +/* + * Conversions between gc.com ID's and GID's + */ +static char GcSet[] = "0123456789ABCDEFGHJKMNPQRTVWXYZ"; +static int GcOffset = 16 * 31 * 31 * 31 - 65536; + +static int +gid2id(char *gid) +{ + char *p; + int i, val; + + if (strncmp(gid, "GC", 2) != 0) + return -1; + if (strlen(gid) != 6) + return -1; + gid += 2; + + if (strcmp(gid, "G000") < 0) + return strtol(gid, NULL, 16); + + for (val = i = 0; i < 4; ++i) + { + val *= 31; + p = strchr(GcSet, gid[i]); + if (!p) return -1; + val += p - GcSet; + } + return val - GcOffset; +} + +static void +id2gid(char gid[6+1], int id) +{ + gid[0] = 0; + if (id < 0) + return; + else if (id < 65536) + snprintf(gid, 6+1, "GC%04X", id); + else + { + int i; + + id += GcOffset; + gid[0] = 'G'; + gid[1] = 'C'; + for (i = 5; i >= 2; --i) { + gid[i] = GcSet[id%31]; + id /= 31; + } + gid[6] = 0; + if (id) + gid[0] = 0; + } + return; +} + +static void +rd_init(const char *fname) +{ + FileIn = xfopen(fname, "rb", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(FileIn); + ARG_FREE(Arg_dbname); + ARG_FREE(Arg_category); +} + +static void +wr_init(const char *fname) +{ + FileOut = xfopen(fname, "wb", MYNAME); + FilenameOut = fname; +} + +static void +wr_deinit(void) +{ + fclose(FileOut); + ARG_FREE(Arg_dbname); + ARG_FREE(Arg_category); +} + +static char * +field(char **pp, int *lenp) +{ + int len = *lenp; + char *p = *pp; + char *dp, *dbuf; + int state = 0; + + if (len == 0 || *p == 0) + return NULL; + + dbuf = dp = xmalloc(len); + while (len) + { + char ch; + + ch = *p++; + --len; + if (ch == 0 || len == 0) + break; + switch (state) + { + case 0: + if (ch == '\\') + state = 1; + else if (ch == ',') + goto eof; + else + *dp++ = ch; + break; + default: + *dp++ = ch; + state = 0; + break; + } + } +eof: + *dp++ = 0; + dbuf = xrealloc(dbuf, dp - dbuf); + /* fprintf(stderr, "<%.8s> dbuf=%x, len=%d\n", *pp, dbuf, len); */ + *pp = p; + *lenp = len; + return dbuf; +} + +static void +data_read(void) +{ + struct pdb *pdb; + struct pdb_record *pdb_rec; + + if (NULL == (pdb = pdb_Read(fileno(FileIn)))) + fatal(MYNAME ": pdb_Read failed\n"); + + if ((pdb->creator != MYCREATOR) || (pdb->type != MYTYPE)) + fatal(MYNAME ": Not a GeoNiche file.\n"); + + /* Process record 0 */ + pdb_rec = pdb->rec_index.rec; + if (strcmp(pdb_rec->data, Rec0Magic)) + fatal(MYNAME ": Bad record 0, not a GeoNiche file.\n"); + pdb_rec = pdb_rec->next; + + /* Process the rest of the records */ + for (; pdb_rec; pdb_rec = pdb_rec->next) + { + waypoint *wpt; + char *vdata; + int vlen; + char *p; + + int id; + int route_id; + char *title; + char *category; + double lat, lon, alt; + char *datestr, *timestr; + int icon; + char *notes; + char gid[6+1]; + struct tm tm; + + wpt = xcalloc(sizeof(*wpt), 1); + if (!wpt) + fatal(MYNAME ": Couldn't allocate waypoint.\n"); + vdata = (char *) pdb_rec->data; + vlen = pdb_rec->data_len; + + /* Field 1: Target */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 1.\n"); + if (strcmp(p, "Route") == 0) + fatal(MYNAME ": Route record type is not implemented.\n"); + if (strcmp(p, "Target")) + fatal(MYNAME ": Unknown record type '%s'.\n", p); + xfree(p); + + /* Field 2: Import ID number */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 2.\n"); + id = atoi(p); + xfree(p); + + /* Field 3: Title */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 3.\n"); + title = p; + + /* Field 4: Route ID number */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 4.\n"); + route_id = atoi(p); + xfree(p); + + /* Field 5: Category */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 5.\n"); + category = p; + + /* Field 6: Latitude */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 6.\n"); + lat = atof(p); + xfree(p); + + /* Field 7: Longitude */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 7.\n"); + lon = atof(p); + xfree(p); + + /* Field 8: Altitude */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 8.\n"); + alt = atof(p); + xfree(p); + + /* Field 9: Creation date */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 9.\n"); + datestr = p; + + /* Field 10: Creation time */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 10.\n"); + timestr = p; + + /* Field 11: Visited date */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 11.\n"); + xfree(p); + + /* Field 12: Visited time */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 12.\n"); + xfree(p); + + /* Field 13: Icon color (R G B) */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 13.\n"); + xfree(p); + + /* Field 14: icon number */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 14.\n"); + icon = atoi(p); + xfree(p); + + /* Field 15: unused */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 15.\n"); + xfree(p); + + /* Field 16: unused */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 16.\n"); + xfree(p); + + /* Field 17: unused */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 17.\n"); + xfree(p); + + /* Field 18: Notes */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 18.\n"); + notes = p; + + sscanf(datestr, "%d/%d/%d", &tm.tm_mon, &tm.tm_mday, &tm.tm_year); + tm.tm_mon -= 1; + tm.tm_year -= 1900; + sscanf(timestr, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + wpt->creation_time = mktime(&tm); + xfree(datestr); + xfree(timestr); + + id2gid(gid, id); + wpt->latitude = lat; + wpt->longitude = lon; + wpt->altitude = alt; + wpt->icon_descr = category; + wpt->icon_descr_is_dynamic = 1; + + if (gid[0]) + { + wpt->shortname = xstrdup(gid); + wpt->description = title; + wpt->notes = notes; + } + else + { + wpt->shortname = xstrdup(title); + wpt->description = title; + wpt->notes = notes; + } + + waypt_add(wpt); + } + free_pdb(pdb); +} + +static char * +enscape(char *s) +{ + char *buf, *d; + + if (!s) + { + d = xmalloc(1); + *d = 0; + return d; + } + buf = d = xmalloc(strlen(s) * 2 + 1); + for (; *s; ++s) + { + if (*s == '\\' || *s == ',') + *d++ = '\\'; + *d++ = *s; + } + + *d = 0; + return buf; +} + +/* + * Attempt to map an icon description into a GeoNiche icon number + */ +static int +wpt2icon(const waypoint *wpt) +{ + const char *desc = wpt->icon_descr; + + if (!desc) return 0; + else if (strstr(desc, "reg")) return 43; + else if (strstr(desc, "trad")) return 43; + else if (strstr(desc, "multi")) return 44; + else if (strstr(desc, "offset")) return 44; + else if (strstr(desc, "virt")) return 45; + else if (strstr(desc, "loca")) return 45; + else if (strstr(desc, "event")) return 46; + else if (strstr(desc, "lett")) return 47; + else if (strstr(desc, "hyb")) return 47; + else if (strstr(desc, "unk")) return 48; + else if (strstr(desc, "cam")) return 49; + else return 0; +} + +static void +copilot_writewpt(const waypoint *wpt) +{ + static int ct = 0; + struct pdb_record *opdb_rec; + int vlen; + static int vsize = 4096; + char *vdata; + char *title; + struct tm tm; + char datestr[10+1]; + char timestr[8+1]; + char *notes; + int id; + + if (ct == 0) + { + opdb_rec = new_Record (0, 0, ct++, sizeof(Rec0Magic), Rec0Magic); + if (opdb_rec == NULL) + fatal(MYNAME ": libpdb couldn't create record\n"); + if (pdb_AppendRecord(PdbOut, opdb_rec)) + fatal(MYNAME ": libpdb couldn't append record\n"); + } + + if (wpt->description[0]) + title = enscape(wpt->description); + else + title = enscape(wpt->shortname); + + id = gid2id(wpt->shortname); + if (id < 0) + id = ct; + + tm = *localtime(&wpt->creation_time); + strftime(datestr, sizeof(datestr), "%m/%d/%Y", &tm); + strftime(timestr, sizeof(timestr), "%H:%M:%S", &tm); + + /* Notes field MUST have soemthing in it */ + if (!wpt->notes || wpt->notes[0] == 0) + notes = xstrdup(title); + else + notes = enscape(wpt->notes); + + vdata = (char *) xmalloc(vsize); + if (vdata == NULL) + fatal(MYNAME ": libpdb couldn't get record memory\n"); + + for (;;) + { + vlen = snprintf(vdata, vsize, + "Target,%d,%s,,%s,%f,%f,%f,%s,%s,,,,%d,,,,%s" + , id + , title + /* route ID */ + , Arg_category ? Arg_category : "Cache" + , wpt->latitude + , wpt->longitude + , wpt->altitude + , datestr + , timestr + /* visited date */ + /* visited time */ + /* icon color R G B */ + , wpt2icon(wpt) + /* unused1 */ + /* unused2 */ + /* unused3 */ + , notes + ); + + if (vlen > -1 && vlen < vsize) + break; + + /* try again with more space. */ + if (vlen > -1) + vsize = vlen + 1; + else + vsize *= 2; + vdata = (char *) xrealloc(vdata, vsize); + if (vdata == NULL) + fatal(MYNAME ": libpdb couldn't get record memory\n"); + } + + opdb_rec = new_Record (0, 0, ct++, vlen+1, vdata); + + if (opdb_rec == NULL) + fatal(MYNAME ": libpdb couldn't create record\n"); + if (pdb_AppendRecord(PdbOut, opdb_rec)) + fatal(MYNAME ": libpdb couldn't append record\n"); + + xfree(notes); + xfree(title); + xfree(vdata); +} + +static void +data_write(void) +{ + if (NULL == (PdbOut = new_pdb())) + fatal (MYNAME ": new_pdb failed\n"); + + if (Arg_dbname) + strncpy(PdbOut->name, Arg_dbname, PDB_DBNAMELEN); + else + strncpy(PdbOut->name, FilenameOut, PDB_DBNAMELEN); + PdbOut->name[PDB_DBNAMELEN-1] = 0; + + PdbOut->attributes = PDB_ATTR_BACKUP; + PdbOut->ctime = PdbOut->mtime = current_time() + (49*365 + 17*366) * (60*60*24); + PdbOut->type = MYTYPE; + PdbOut->creator = MYCREATOR; + PdbOut->version = 0; + PdbOut->modnum = 1; + + waypt_disp_all(copilot_writewpt); + + pdb_Write(PdbOut, fileno(FileOut)); + + free_pdb(PdbOut); +} + + +ff_vecs_t geoniche_vecs = +{ + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL, + Args +}; diff --git a/gpilots.c b/gpilots.c new file mode 100644 index 000000000..0a95644fb --- /dev/null +++ b/gpilots.c @@ -0,0 +1,419 @@ +/* + Read and write GPilotS files. + + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "coldsync/palm.h" +#include "coldsync/pdb.h" +#include "garmin_tables.h" + +#define MYNAME "GPilotS" +#define MYWPT 0x57707473 /* Wpts */ +#define MYTRK 0x54726b73 /* Trks */ +#define MYRTE 0x57707473 /* Wpts */ +#define MYCREATOR 0x4750696c /* GPil */ + + +/* + * Structures grafted from http://www.cru.fr/perso/cc/GPilotS/ + */ + + +typedef struct +{ + long lat; /* latitude in semicircles */ + long lon; /* longitude in semicircles */ +} +Semicircle_Type; + +typedef struct +{ + char ident[6]; /* identifier */ + unsigned char lat[4]; /* position */ + unsigned char lon[4]; /* position */ + unsigned char unused[4]; /* should be set to zero */ + char cmnt[40]; /* comment */ + unsigned char smbl; /* symbol id */ + unsigned char dspl; /* display option */ +} D103_Wpt_Type; + +typedef union { + float f; + unsigned int i; +} fi_t; + +typedef struct /* size */ +{ + unsigned char wpt_class; /* class (see below) 1 */ + unsigned char color; /* color (see below) 1 */ + unsigned char dspl; /* display options (see below) 1 */ + unsigned char attr; /* attributes (see below) 1 */ + unsigned char smbl[2]; /* waypoint symbol 2 */ + unsigned char subclass[18]; /* subclass 18 */ + unsigned char lat[4]; /* position */ + unsigned char lon[4]; /* position */ + float alt; /* altitude in meters 4 */ + float dpth; /* depth in meters 4 */ + float dist; /* proximity distance in meters 4 */ + char state[2]; /* state 2 */ + char cc[2]; /* country code 2 */ + char varlenstrs[1]; /* start of variable length strings */ + /* G_char ident[]; variable length string 1-51 */ + /* G_char comment[]; waypoint user comment 1-51 */ + /* G_char facility[]; facility name 1-31 */ + /* G_char city[]; city name 1-25 */ + /* G_char addr[]; address number 1-51 */ + /* G_char cross_road[]; intersecting road label 1-51 */ +} +D108_Wpt_Type; + +typedef struct /* structure de waypoint "interne" */ +{ + unsigned char ident[51]; /* identifier (50 + '0') */ + Semicircle_Type posn; /* position (common to all Garmin types) */ + unsigned char cmnt[51]; /* comment (50 + '0') */ + float dst; /* proximity distance */ + float alt; /* altitude */ + int smbl; /* symbol id */ + unsigned char dspl; /* display option */ + unsigned char color; /* color */ +} +Custom_Wpt_Type; + +typedef struct /* internal track header */ +{ + char name[256]; /* nom du groupe de trackpoints */ + unsigned char dspl; /* display on the map ? */ + unsigned char color; /* color */ + unsigned char type; /* type of following track points */ + unsigned char unused; /* type of following track points */ + unsigned char number[2]; /* number of track points */ + unsigned char latmin[4]; /* latitude min */ + unsigned char latmax[4]; /* latitude max */ + unsigned char lonmin[4]; /* longitude min */ + unsigned char lonmax[4]; /* longitude max */ + unsigned char unused2[2]; /* type of following track points */ +} +Custom_Trk_Hdr_Type; + +typedef struct +{ + unsigned char lat[4]; /* position */ + unsigned char lon[4]; /* position */ + unsigned char time[4]; + unsigned char alt[4]; + unsigned char new_trk; + unsigned char unused; +} Custom_Trk_Point_Type; + +typedef struct /* custom compact track point type */ +{ + unsigned char lat[4]; /* position */ + unsigned char lon[4]; /* position */ + unsigned char new_trk; + unsigned char unused; +} Compact_Trk_Point_Type; /* size : 10 bytes */ + +struct record +{ + struct { + unsigned char type; + unsigned short size; + unsigned int version; + } header; + union { + D103_Wpt_Type d103; + D108_Wpt_Type d108; + Custom_Wpt_Type CustWpt; + Custom_Trk_Hdr_Type CustTrkHdr; +#if LATER + Custom_Rte_Hdr_Type CustRteHdr; +#endif + } wpt; +}; + + +static FILE *file_in; +static FILE *file_out; +static const char *out_fname; +struct pdb *opdb; +struct pdb_record *opdb_rec; + +static char *dbname = NULL; + +static +arglist_t my_args[] = { + {"dbname", &dbname, "Database name", NULL, ARGTYPE_STRING}, + {0, 0, 0, 0, 0} +}; + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "rb", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); + if ( dbname ) { + xfree(dbname); + dbname = NULL; + } +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "wb", MYNAME); + out_fname = fname; +} + +static void +wr_deinit(void) +{ + fclose(file_out); + if ( dbname ) { + xfree(dbname); + dbname = NULL; + } +} + +static void +data_read(void) +{ + struct record *rec; + struct pdb *pdb; + struct pdb_record *pdb_rec; + route_head *track_head; + + if (NULL == (pdb = pdb_Read(fileno(file_in)))) { + fatal(MYNAME ": pdb_Read failed\n"); + } + + if (pdb->creator != MYCREATOR) { + fatal(MYNAME ": Not a %s file.\n", MYNAME); + } + + switch(pdb->type) { + case MYWPT: + /* blah */ + break; + case MYTRK: + /* blah */ + break; + default: + fatal(MYNAME ": Unknown file type 0x%x\n", (int) pdb->type); + } + + for(pdb_rec = pdb->rec_index.rec; pdb_rec; pdb_rec=pdb_rec->next) { + waypoint *wpt_tmp; + Custom_Trk_Point_Type *tp_cust; + Compact_Trk_Point_Type *tp_comp; + int lat; + int lon; + int sz; + fi_t fi; + + wpt_tmp = waypt_new(); + + rec = (struct record *) pdb_rec->data; + switch(rec->header.type) { + /* + * G103Type + */ + case 4: + wpt_tmp->shortname = xstrndupt(rec->wpt.d103.ident, sizeof(rec->wpt.d103.ident)); + wpt_tmp->description = xstrndupt(rec->wpt.d103.cmnt, sizeof(rec->wpt.d103.cmnt)); + /* This is odd. This is a Palm DB file, + * yet the data appears to be little endian, + * not appropriate the the actual Palm. + */ + lon = le_read32(&rec->wpt.d103.lon); + lat = le_read32(&rec->wpt.d103.lat); + wpt_tmp->longitude = lon / 2147483648.0 * 180.0; + wpt_tmp->latitude = lat / 2147483648.0 * 180.0; + waypt_add(wpt_tmp); + break; + /* + * G108Type + */ + case 9: + wpt_tmp->shortname = xstrndupt(rec->wpt.d108.varlenstrs, 50); + wpt_tmp->description = xstrndupt(rec->wpt.d108.varlenstrs + strlen(wpt_tmp->shortname) + 1, 50); + /* This is odd. This is a Palm DB file, + * yet the data appears to be little endian, + * not appropriate the the actual Palm. + */ + lon = le_read32(&rec->wpt.d108.lon); + lat = le_read32(&rec->wpt.d108.lat); + wpt_tmp->longitude = lon / 2147483648.0 * 180.0; + wpt_tmp->latitude = lat / 2147483648.0 * 180.0; + fi.i = le_read32(&rec->wpt.d108.alt); + wpt_tmp->altitude = fi.f; + fi.i = le_read32(&rec->wpt.d108.dpth); + wpt_tmp->depth = fi.f; + fi.i = le_read32(&rec->wpt.d108.dist); + wpt_tmp->proximity = fi.f; + wpt_tmp->icon_descr_is_dynamic = 0; + wpt_tmp->icon_descr = mps_find_desc_from_icon_number((rec->wpt.d108.smbl[1] << 8) + rec->wpt.d108.smbl[0], PCX); + waypt_add(wpt_tmp); + break; + + /* + * CustomTrkHdr + */ + case 101: + track_head = route_head_alloc(); + track_add_head(track_head); + track_head->rte_name = xstrndup(rec->wpt.CustTrkHdr.name, sizeof(rec->wpt.CustTrkHdr.name)); + sz = be_read16(&rec->wpt.CustTrkHdr.number); + + /* switch between custom track points and compact track points. + * (compact points have no altitude and time info. + */ + switch (rec->wpt.CustTrkHdr.type) { + case 102: + tp_cust = (Custom_Trk_Point_Type *) ((char *) pdb_rec->data + sizeof(rec->header) + sizeof(rec->wpt.CustTrkHdr)); + while (sz--) { + wpt_tmp = waypt_new(); + /* This is even more odd. + * Track data is stored as big endian while + * waypoint data is little endian!? + */ + lon = be_read32(&tp_cust->lon); + lat = be_read32(&tp_cust->lat); + wpt_tmp->longitude = lon / 2147483648.0 * 180.0; + wpt_tmp->latitude = lat / 2147483648.0 * 180.0; + /* + * Convert Garmin/GPilotS time format to gpsbabel time format. + * Garmin/GPilotS count seconds from "UTC 12:00 AM December 31 1989". + * gpsbabel counts seconds from "UTC 12:00 AM January 1 1970". + */ + wpt_tmp->creation_time = be_read32(&tp_cust->time) + 631065600; + fi.i = be_read32(&tp_cust->alt); + wpt_tmp->altitude = fi.f; + route_add_wpt(track_head, wpt_tmp); + tp_cust++; + } + break; + case 104: + tp_comp = (Compact_Trk_Point_Type *) ((char *) pdb_rec->data + sizeof(rec->header) + sizeof(rec->wpt.CustTrkHdr)); + while (sz--) { + wpt_tmp = waypt_new(); + lon = be_read32(&tp_comp->lon); + lat = be_read32(&tp_comp->lat); + wpt_tmp->longitude = lon / 2147483648.0 * 180.0; + wpt_tmp->latitude = lat / 2147483648.0 * 180.0; + route_add_wpt(track_head, wpt_tmp); + tp_comp++; + } + break; + default: + fatal(MYNAME ": track point type %d not supported.\n", rec->wpt.CustTrkHdr.type); + } + break; + default: + fatal(MYNAME ": input record type %d not supported.\n", rec->header.type); + } + + } + free_pdb(pdb); +} + + +struct hdr{ + char *wpt_name; + waypoint *wpt; +}; + +static void +my_write_wpt(const waypoint *wpt) +{ + struct record *rec; + static int ct; + char *vdata; + int lat, lon; + + rec = xcalloc(sizeof *rec, 1); + vdata = (char *)rec + sizeof (*rec); + + rec->header.type = 4; + strncpy(rec->wpt.d103.ident, wpt->shortname, sizeof(rec->wpt.d103.ident)); + strncpy(rec->wpt.d103.cmnt, wpt->description, sizeof(rec->wpt.d103.cmnt)); + lat = wpt->latitude / 180.0 * 2147483648.0; + lon = wpt->longitude / 180.0 * 2147483648.0; + le_write32(&rec->wpt.d103.lat, lat); + le_write32(&rec->wpt.d103.lon, lon); + + opdb_rec = new_Record(0, 0, ct++, vdata - (char *) rec, (const ubyte *) rec); + + if (opdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create record\n"); + } + + if (pdb_AppendRecord(opdb, opdb_rec)) { + fatal(MYNAME ": libpdb couldn't append record\n"); + } + xfree(rec); +} + +static void +data_write(void) +{ + if (NULL == (opdb = new_pdb())) { + fatal (MYNAME ": new_pdb failed\n"); + } + + if ( dbname ) { + strncpy( opdb->name, dbname, PDB_DBNAMELEN ); + } else { + strncpy(opdb->name, out_fname, PDB_DBNAMELEN); + } + + /* + * Populate header. + */ + opdb->name[PDB_DBNAMELEN-1] = 0; + opdb->attributes = PDB_ATTR_BACKUP; + opdb->ctime = opdb->mtime = current_time() + 2082844800U; + + opdb->type = MYWPT; + opdb->creator = MYCREATOR; + opdb->version = 1; + + waypt_disp_all(my_write_wpt); + + pdb_Write(opdb, fileno(file_out)); +} + + +ff_vecs_t gpilots_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL, + my_args +}; diff --git a/gpsman b/gpsman new file mode 100644 index 000000000..771a261f5 --- /dev/null +++ b/gpsman @@ -0,0 +1,53 @@ +% Written by GPSManager 05-Apr-2002 21:52:36 (EST) +% Edit at your own risk! + +!Format: DMS 1 WGS 84 +!Creation: no + +!W: +GC894 N41 20 07.9 W85 24 31.9 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC1F78 N40 43 04.1 W85 06 25.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +003 N41 07 21.3 W85 09 23.5 symbol=boat_ramp alt=220.506469727 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC93 N41 43 09.4 W85 58 59.9 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2193 N40 25 29.0 W86 54 52.0 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +004 N41 07 22.6 W85 09 24.3 symbol=flag alt=250.787719727 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GCA80 N40 29 14.3 W86 51 50.5 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC28CB N40 50 32.8 W85 25 20.8 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2665 N40 45 56.4 W85 35 58.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +005 N41 02 51.4 W85 16 41.6 symbol=flag alt=263.044433594 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GCB78 N40 26 17.9 W86 54 02.2 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2ADC N40 26 16.4 W86 48 21.6 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +ABACUS N41 04 20.6 W85 13 50.8 symbol=building alt=243.577880859 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GCD85 N41 05 03.3 W85 08 11.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GCB8 N40 26 09.5 W87 09 49.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2BE8 N40 52 45.9 W85 32 26.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +CASH1 N41 04 41.8 W85 08 19.3 symbol=flag alt=245.740844727 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +H0ME N41 02 51.7 W85 16 42.1 symbol=house alt=272.176879883 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2C81 N41 12 24.2 W85 02 23.5 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +CENCEN N41 41 39.0 W86 14 53.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +TOSB2 N41 44 00.4 W84 59 46.4 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2C90 N40 50 08.2 W85 27 14.9 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +CWORK N41 07 23.0 W85 09 24.7 symbol=flag alt=254.633056641 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +TOSB3 N41 43 21.9 W86 15 20.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2C91 N41 05 01.4 W85 08 18.7 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB1 N41 40 34.1 W86 15 01.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +UNITA N41 02 52.2 W85 16 41.6 symbol=flag alt=256.795898438 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2F53 N41 43 57.0 W86 04 48.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB2 N41 38 10.3 W86 15 04.4 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC333A N41 01 42.7 W85 11 49.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB4 N41 37 27.7 W86 15 08.7 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB5 N41 38 53.4 W85 56 55.0 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC34D4 N41 58 16.8 W86 11 05.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB6 N41 34 46.3 W85 50 01.8 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC42A1 N41 05 02.1 W85 03 14.2 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC37C4 N41 38 15.5 W85 54 19.6 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB7 N41 07 42.2 W85 11 47.8 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC4378 N40 53 27.2 W85 28 13.4 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC11EF N40 01 45.3 W86 53 17.4 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC44E5 N41 01 03.7 W85 15 07.0 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC12FF N41 33 23.9 W86 21 26.9 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC47A5 N40 25 15.3 W86 54 17.6 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC17E0 N41 52 01.5 W86 36 12.5 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC488D N41 33 43.7 W85 50 18.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC1A9C N41 06 36.2 W85 09 20.8 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA + diff --git a/gpsman2 b/gpsman2 new file mode 100644 index 000000000..4cf6db838 --- /dev/null +++ b/gpsman2 @@ -0,0 +1,75 @@ +% Written by GPSManager 24-May-2002 13:51:04 (CST) +% Edit at your own risk! + +!Format: DMM 1 WGS 84 +!Creation: no + +!W: +!Position: DMS +GC37C4 N41 38 15.5 W85 54 19.6 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +H0ME N41 02 51.7 W85 16 42.1 symbol=house alt=272.176879883 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC894 N41 20 07.9 W85 24 31.9 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB7 N41 07 42.2 W85 11 47.8 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2C81 N41 12 24.2 W85 02 23.5 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC1F78 N40 43 04.1 W85 06 25.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC4378 N40 53 27.2 W85 28 13.4 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +TOSB2 N41 44 00.4 W84 59 46.4 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +CENCEN N41 41 39.0 W86 14 53.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +003 N41 07 21.3 W85 09 23.5 symbol=boat_ramp alt=220.506469727 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC11EF N40 01 45.3 W86 53 17.4 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2C90 N40 50 08.2 W85 27 14.9 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC93 N41 43 09.4 W85 58 59.9 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC12FF N41 33 23.9 W86 21 26.9 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC44E5 N41 01 03.7 W85 15 07.0 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +CWORK N41 07 23.0 W85 09 24.7 symbol=flag alt=254.633056641 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2193 N40 25 29.0 W86 54 52.0 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC47A5 N40 25 15.3 W86 54 17.6 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +TOSB3 N41 43 21.9 W86 15 20.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +004 N41 07 22.6 W85 09 24.3 symbol=flag alt=250.787719727 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC17E0 N41 52 01.5 W86 36 12.5 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2C91 N41 05 01.4 W85 08 18.7 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GCA80 N40 29 14.3 W86 51 50.5 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC488D N41 33 43.7 W85 50 18.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB1 N41 40 34.1 W86 15 01.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC28CB N40 50 32.8 W85 25 20.8 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC1A9C N41 06 36.2 W85 09 20.8 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +UNITA N41 02 52.2 W85 16 41.6 symbol=flag alt=256.795898438 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2665 N40 45 56.4 W85 35 58.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2F53 N41 43 57.0 W86 04 48.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +005 N41 02 51.4 W85 16 41.6 symbol=flag alt=263.044433594 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GCB78 N40 26 17.9 W86 54 02.2 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB2 N41 38 10.3 W86 15 04.4 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2ADC N40 26 16.4 W86 48 21.6 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB4 N41 37 27.7 W86 15 08.7 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC333A N41 01 42.7 W85 11 49.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +ABACUS N41 04 20.6 W85 13 50.8 symbol=building alt=243.577880859 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB5 N41 38 53.4 W85 56 55.0 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GCD85 N41 05 03.3 W85 08 11.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC34D4 N41 58 16.8 W86 11 05.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GCB8 N40 26 09.5 W87 09 49.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB6 N41 34 46.3 W85 50 01.8 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC2BE8 N40 52 45.9 W85 32 26.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC42A1 N41 05 02.1 W85 03 14.2 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +CASH1 N41 04 41.8 W85 08 19.3 symbol=flag alt=245.740844727 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA + +!Position: DMM +!R: 34 +!Position: DMS +003 N41 07 21.3 W85 09 23.5 symbol=boat_ramp alt=220.506469727 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +004 N41 07 22.6 W85 09 24.3 symbol=flag alt=250.787719727 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +005 N41 02 51.4 W85 16 41.6 symbol=flag alt=263.044433594 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +ABACUS N41 04 20.6 W85 13 50.8 symbol=building alt=243.577880859 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +CASH1 N41 04 41.8 W85 08 19.3 symbol=flag alt=245.740844727 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +CENCEN N41 41 39.0 W86 14 53.3 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +CWORK N41 07 23.0 W85 09 24.7 symbol=flag alt=254.633056641 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +FRSB1 N41 40 34.1 W86 15 01.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC11EF N40 01 45.3 W86 53 17.4 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GCD85 N41 05 03.3 W85 08 11.1 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA + +!R: 23 Route 23 +!NB: blah blah blah + +GC11EF N40 01 45.3 W86 53 17.4 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC12FF N41 33 23.9 W86 21 26.9 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA +GC1A9C N41 06 36.2 W85 09 20.8 alt=-0.114379882812 GD108:class=|c! GD108:colour=~|Z GD108:attrs=` GD108:depth=QY|c%|_i GD108:state=|cAA GD108:country=|cAA + diff --git a/gpspilot.c b/gpspilot.c new file mode 100644 index 000000000..7863af855 --- /dev/null +++ b/gpspilot.c @@ -0,0 +1,258 @@ +/* + Read and write GPSPilot Tracker files. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "coldsync/palm.h" +#include "coldsync/pdb.h" + +#define MYNAME "GPSPilot" +#define MYTYPE_POINTS 0x706f696e /* poin */ +#define MYTYPE_AIRPORT 0x706f3030 /* po00 */ +#define MYTYPE_CITIES 0x706f3031 /* po01 */ +#define MYTYPE_LNDMRKS 0x706f3032 /* po02 */ +#define MYTYPE_NAVAIDS 0x706f3033 /* po03 */ +#define MYCREATOR 0x47704c69 /* GpLi */ + +struct record { + pdb_32 longitude; /* Big endian, long * 3.6e6 */ + pdb_32 latitude; /* similarly */ + pdb_16 elevation; /* meters */ + pdb_16 magvar; /* magnetic variation in degrees, neg = west */ +}; + +struct runways { + pdb_32 be_longitude; /* Big endian, long * 3.6e6 */ + pdb_32 be_latitude; /* similarly */ + pdb_32 en_longitude; /* Big endian, long * 3.6e6 */ + pdb_32 en_latitude; /* similarly */ +}; + +static FILE *file_in; +static FILE *file_out; +static const char *out_fname; +struct pdb *opdb; +struct pdb_record *opdb_rec; +static char *dbname = NULL; + +static +arglist_t gpspilot_args[] = { + {"dbname", &dbname, "Database name", NULL, ARGTYPE_STRING}, + {0, 0, 0, 0, 0} +}; + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "rb", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); + if ( dbname ) { + xfree(dbname); + dbname = NULL; + } +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "wb", MYNAME); + out_fname = fname; +} + +static void +wr_deinit(void) +{ + fclose(file_out); + if ( dbname ) { + xfree(dbname); + dbname = NULL; + } +} + +static void +data_read(void) +{ + struct record *rec; + struct pdb *pdb; + struct pdb_record *pdb_rec; + + if (NULL == (pdb = pdb_Read(fileno(file_in)))) { + fatal(MYNAME ": pdb_Read failed\n"); + } + + if ((pdb->creator != MYCREATOR)) { + fatal(MYNAME ": Not a gpspilot file.\n"); + } + + switch (pdb->type) + { + case MYTYPE_AIRPORT: + case MYTYPE_POINTS: + case MYTYPE_CITIES: + case MYTYPE_LNDMRKS: + case MYTYPE_NAVAIDS: + break; + default: + fatal(MYNAME ": Not a gpspilot file.\n"); + } + + for(pdb_rec = pdb->rec_index.rec; pdb_rec; pdb_rec=pdb_rec->next) { + waypoint *wpt_tmp; + char *vdata; + + wpt_tmp = xcalloc(sizeof(*wpt_tmp),1); + + rec = (struct record *) pdb_rec->data; + wpt_tmp->longitude = be_read32(&rec->longitude) / 3.6e6; + wpt_tmp->latitude = be_read32(&rec->latitude) / 3.6e6; + wpt_tmp->altitude = + be_read16(&rec->elevation); + + vdata = (char *) pdb_rec->data + sizeof(*rec); + + /* + * skip runway records if an airport. + */ + if (pdb_rec->category == 0) + { + int numRunways; + numRunways = be_read16(vdata); + vdata += 2; + vdata += (sizeof(struct runways) * numRunways); + } + + /* + * This maping is a bit contrived. + * Name is up to 36. ID is up to 9. + * Since 'ID' maps more clearly to "shortname" (and this + * more likely to be resemble a wayoint name in another + * receiver) we use that for shortname and use 'name' as + * our description. + */ + wpt_tmp->description = xstrdup(vdata); + vdata = vdata + strlen(vdata) + 1; + + wpt_tmp->shortname = xstrdup(vdata); + vdata = vdata + strlen(vdata) + 1; + + wpt_tmp->notes = xstrdup(vdata); + + waypt_add(wpt_tmp); + + } + free_pdb(pdb); +} + + +static void +gpspilot_writewpt(const waypoint *wpt) +{ + struct record *rec; + static int ct = 0; + char *vdata; + + rec = xcalloc(sizeof(*rec)+206,1); + + be_write32(&rec->longitude, si_round(wpt->longitude * 3.6e6)); + be_write32(&rec->latitude, si_round(wpt->latitude * 3.6e6)); + be_write16(&rec->elevation, si_round(wpt->altitude)); + be_write16(&rec->magvar, 0 ); + + vdata = (char *)rec + sizeof(*rec); + if ( wpt->description ) { + strncpy( vdata, wpt->description, 36 ); + vdata[35] = '\0'; + } + else { + vdata[0] ='\0'; + } + vdata += strlen( vdata ) + 1; + if ( wpt->shortname ) { + strncpy( vdata, wpt->shortname, 9 ); + vdata[8] = '\0'; + } + else { + vdata[0] ='\0'; + } + vdata += strlen( vdata ) + 1; + + if ( wpt->notes ) { + strncpy( vdata, wpt->notes, 161 ); + vdata[160] = '\0'; + } + else { + vdata[0] ='\0'; + } + vdata += strlen( vdata ) + 1; + + opdb_rec = new_Record (0, 2, ct++, vdata-(char *)rec, (const ubyte *)rec); + + if (opdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create record\n"); + } + + if (pdb_AppendRecord(opdb, opdb_rec)) { + fatal(MYNAME ": libpdb couldn't append record\n"); + } + xfree(rec); +} + +static void +data_write(void) +{ + if (NULL == (opdb = new_pdb())) { + fatal (MYNAME ": new_pdb failed\n"); + } + + if ( dbname ) { + strncpy(opdb->name, dbname, PDB_DBNAMELEN); + } + else { + strncpy(opdb->name, out_fname, PDB_DBNAMELEN); + } + opdb->name[PDB_DBNAMELEN-1] = 0; + opdb->attributes = PDB_ATTR_BACKUP; + opdb->ctime = opdb->mtime = current_time() + 2082844800U; + opdb->type = MYTYPE_POINTS; + opdb->creator = MYCREATOR; + opdb->version = 0; + + waypt_disp_all(gpspilot_writewpt); + + pdb_Write(opdb, fileno(file_out)); +} + + +ff_vecs_t gpspilot_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL, + gpspilot_args +}; diff --git a/gpsutil.c b/gpsutil.c new file mode 100644 index 000000000..eeec5659f --- /dev/null +++ b/gpsutil.c @@ -0,0 +1,151 @@ +/* + Access gpsutil files. + + Copyright (C) 2002, 2003, 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include "defs.h" +#include "magellan.h" + +static FILE *file_in; +static FILE *file_out; +static void *mkshort_handle; + +#define MYNAME "GPSUTIL" + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "r", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "w", MYNAME); + mkshort_handle = mkshort_new_handle(); +} + +static void +wr_deinit(void) +{ + fclose(file_out); + mkshort_del_handle(mkshort_handle); +} + +static void +data_read(void) +{ + char ibuf[100]; + char name[9], desc[30]; + double lat,lon; + char latdir, londir; + int ilat, ilon; + long alt; + char alttype; + char icon[3] = {0}; + waypoint *wpt_tmp; + /* + * Make sure that all waypoints in single read have same + * timestamp. + */ + time_t now = current_time(); + + + for(;fgets(ibuf, sizeof(ibuf), file_in);) { + /* A sharp in column zero or an blank line is a comment */ + if (ibuf[0] == '#' || ibuf[0] == '\n') continue; + sscanf(ibuf, "%s %le%c %le%c %ld%c %30[^,] %c", + name, &lat, &latdir, &lon, &londir, + &alt, &alttype, desc, icon); + desc[0] = '\0'; + icon[0] = '\0'; + sscanf(&ibuf[39], "%30c", desc); + sscanf(&ibuf[70], "%2c", icon); + rtrim(desc); + rtrim(icon); + wpt_tmp = xcalloc(sizeof(*wpt_tmp),1); + wpt_tmp->altitude = alt; + wpt_tmp->shortname = xstrdup(name); + wpt_tmp->description = xstrdup(desc); + wpt_tmp->creation_time = now; + + if (latdir == 'S') lat = -lat; + if (londir == 'W') lon = -lon; + + lat /= 100.0; + lon /= 100.0; + ilon = (int)(lon); + wpt_tmp->longitude = ilon + (lon - ilon)*(100.0/60.0); + ilat = (int)(lat); + wpt_tmp->latitude = ilat + (lat - ilat) * (100.0/60.0); + wpt_tmp->icon_descr = mag_find_descr_from_token(icon); + waypt_add(wpt_tmp); + } +} + +static void +gpsutil_disp(const waypoint *wpt) +{ + double lon,lat; + const char *icon_token; + char *tdesc = str_utf8_to_ascii(wpt->description); + + icon_token = mag_find_token_from_descr(wpt->icon_descr); + + lon = degrees2ddmm(wpt->longitude); + lat = degrees2ddmm(wpt->latitude); + + fprintf(file_out, "%-8s %08.3f%c %09.3f%c %07.0f%c %-30.30s %s\n", + global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, wpt->description) : + wpt->shortname, + fabs(lat), + lat < 0.0 ? 'S' : 'N', + fabs(lon), + lon < 0.0 ? 'W' : 'E', + wpt->altitude == unknown_alt ? 0 : wpt->altitude, + 'm', + wpt->description ? tdesc : "", + icon_token); + + xfree(tdesc); +} + +static void +data_write(void) +{ + waypt_disp_all(gpsutil_disp); +} + + +ff_vecs_t gpsutil_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL +}; diff --git a/gpx.c b/gpx.c new file mode 100644 index 000000000..7b9830da3 --- /dev/null +++ b/gpx.c @@ -0,0 +1,1315 @@ +/* + Access GPX data files. + + Copyright (C) 2002, 2003, 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#ifndef NO_EXPAT + #include + static XML_Parser psr; +#endif + +static xml_tag *cur_tag; +static vmem_t cdatastr; +static char *opt_logpoint = NULL; +static int logpoint_ct = 0; + +static const char *gpx_version; +static const char *gpx_creator; +static char *xsi_schema_loc; + +static char *gpx_email = NULL; +static char *gpx_author = NULL; +vmem_t current_tag; + +static waypoint *wpt_tmp; +static int cache_descr_is_html; +static FILE *fd; +static FILE *ofd; +static void *mkshort_handle; + +static const char *input_string = NULL; +static int input_string_len = 0; + +static time_t file_time; + +static char *gsshortnames = NULL; +static char *snlen = NULL; +static char *suppresswhite = NULL; +static char *urlbase = NULL; +static route_head *trk_head; +static route_head *rte_head; + +#define MYNAME "GPX" +#define MY_CBUF 4096 +#define DEFAULT_XSI_SCHEMA_LOC "http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd" + +typedef enum { + tt_unknown = 0, + tt_gpx, + tt_author, + tt_desc, + tt_email, + tt_time, + tt_wpt, + tt_wpt_cmt, + tt_wpt_desc, + tt_wpt_name, + tt_wpt_sym, + tt_wpt_url, + tt_wpt_ele, + tt_wpt_time, + tt_wpt_type, + tt_wpt_urlname, + tt_cache, + tt_cache_name, + tt_cache_container, + tt_cache_type, + tt_cache_difficulty, + tt_cache_terrain, + tt_cache_hint, + tt_cache_desc_short, + tt_cache_desc_long, + tt_cache_log_wpt, + tt_rte, + tt_rte_name, + tt_rte_desc, + tt_rte_cmt, + tt_rte_number, + tt_rte_rtept, + tt_rte_rtept_ele, + tt_rte_rtept_name, + tt_rte_rtept_desc, + tt_rte_rtept_sym, + tt_rte_rtept_time, + tt_rte_rtept_cmt, + tt_rte_rtept_url, + tt_rte_rtept_urlname, + tt_trk, + tt_trk_desc, + tt_trk_name, + tt_trk_trkseg, + tt_trk_number, + tt_trk_trkseg_trkpt, + tt_trk_trkseg_trkpt_cmt, + tt_trk_trkseg_trkpt_name, + tt_trk_trkseg_trkpt_sym, + tt_trk_trkseg_trkpt_url, + tt_trk_trkseg_trkpt_urlname, + tt_trk_trkseg_trkpt_desc, + tt_trk_trkseg_trkpt_ele, + tt_trk_trkseg_trkpt_time, +} tag_type; + +typedef struct tag_mapping { + tag_type tag_type; /* enum from above for this tag */ + int tag_passthrough; /* true if we don't generate this */ + const char *tag_name; /* xpath-ish tag name */ +} tag_mapping; + +/* + * xpath(ish) mappings between full tag paths and internal identifers. + * These appear in the order they appear in the GPX specification. + * If it's not a tag we explictly handle, it doesn't go here. + */ + +tag_mapping tag_path_map[] = { + { tt_gpx, 0, "/gpx" }, + { tt_time, 0, "/gpx/time" }, + { tt_author, 0, "/gpx/author" }, + { tt_email, 0, "/gpx/email" }, + { tt_time, 0, "/gpx/time" }, + { tt_desc, 0, "/gpx/desc" }, + + { tt_wpt, 0, "/gpx/wpt" }, + { tt_wpt_ele, 0, "/gpx/wpt/ele" }, + { tt_wpt_time, 0, "/gpx/wpt/time" }, + { tt_wpt_name, 0, "/gpx/wpt/name" }, + { tt_wpt_cmt, 0, "/gpx/wpt/cmt" }, + { tt_wpt_desc, 0, "/gpx/wpt/desc" }, + { tt_wpt_url, 0, "/gpx/wpt/url" }, + { tt_wpt_urlname, 0, "/gpx/wpt/urlname" }, + { tt_wpt_sym, 0, "/gpx/wpt/sym" }, + { tt_wpt_type, 1, "/gpx/wpt/type" }, + { tt_cache, 1, "/gpx/wpt/groundspeak:cache" }, + { tt_cache_name, 1, "/gpx/wpt/groundspeak:cache/groundspeak:name" }, + { tt_cache_container, 1, "/gpx/wpt/groundspeak:cache/groundspeak:container" }, + { tt_cache_type, 1, "/gpx/wpt/groundspeak:cache/groundspeak:type" }, + { tt_cache_difficulty, 1, "/gpx/wpt/groundspeak:cache/groundspeak:difficulty" }, + { tt_cache_terrain, 1, "/gpx/wpt/groundspeak:cache/groundspeak:terrain" }, + { tt_cache_hint, 1, "/gpx/wpt/groundspeak:cache/groundspeak:encoded_hints" }, + { tt_cache_desc_short, 1, "/gpx/wpt/groundspeak:cache/groundspeak:short_description" }, + { tt_cache_desc_long, 1, "/gpx/wpt/groundspeak:cache/groundspeak:long_description" }, + { tt_cache_log_wpt, 1, "/gpx/wpt/groundspeak:cache/groundspeak:logs/groundspeak:log/groundspeak:log_wpt" }, + + { tt_rte, 0, "/gpx/rte" }, + { tt_rte_name, 0, "/gpx/rte/name" }, + { tt_rte_desc, 0, "/gpx/rte/desc" }, + { tt_rte_number, 0, "/gpx/rte/number" }, + { tt_rte_rtept, 0, "/gpx/rte/rtept" }, + { tt_rte_rtept_ele, 0, "/gpx/rte/rtept/ele" }, + { tt_rte_rtept_time, 0, "/gpx/rte/rtept/time" }, + { tt_rte_rtept_name, 0, "/gpx/rte/rtept/name" }, + { tt_rte_rtept_cmt, 0, "/gpx/rte/rtept/cmt" }, + { tt_rte_rtept_desc, 0, "/gpx/rte/rtept/desc" }, + { tt_rte_rtept_url, 0, "/gpx/rte/rtept/url" }, + { tt_rte_rtept_urlname, 0, "/gpx/rte/rtept/urlname" }, + { tt_rte_rtept_sym, 0, "/gpx/rte/rtept/sym" }, + + { tt_trk, 0, "/gpx/trk" }, + { tt_trk_name, 0, "/gpx/trk/name" }, + { tt_trk_desc, 0, "/gpx/trk/desc" }, + { tt_trk_trkseg, 0, "/gpx/trk/trkseg" }, + { tt_trk_number, 0, "/gpx/trk/number" }, + { tt_trk_trkseg_trkpt, 0, "/gpx/trk/trkseg/trkpt" }, + { tt_trk_trkseg_trkpt_ele, 0, "/gpx/trk/trkseg/trkpt/ele" }, + { tt_trk_trkseg_trkpt_time, 0, "/gpx/trk/trkseg/trkpt/time" }, + { tt_trk_trkseg_trkpt_name, 0, "/gpx/trk/trkseg/trkpt/name" }, + { tt_trk_trkseg_trkpt_cmt, 0, "/gpx/trk/trkseg/trkpt/cmt" }, + { tt_trk_trkseg_trkpt_desc, 0, "/gpx/trk/trkseg/trkpt/desc" }, + { tt_trk_trkseg_trkpt_url, 0, "/gpx/trk/trkseg/trkpt/url" }, + { tt_trk_trkseg_trkpt_urlname, 0, "/gpx/trk/trkseg/trkpt/urlname" }, + { tt_trk_trkseg_trkpt_sym, 0, "/gpx/trk/trkseg/trkpt/sym" }, + {0} +}; + + +static void +write_xml_entity(FILE *ofd, const char *indent, + const char *tag, const char *value) +{ + char *tmp_ent = xml_entitize(value); + fprintf(ofd, "%s<%s>%s\n", indent, tag, tmp_ent, tag); + xfree(tmp_ent); +} + +static void +write_optional_xml_entity(FILE *ofd, const char *indent, + const char *tag, const char *value) +{ + if (value && *value) + write_xml_entity(ofd, indent, tag, value); +} + +static tag_type +get_tag(const char *t, int *passthrough) +{ + tag_mapping *tm; + for (tm = tag_path_map; tm->tag_type != 0; tm++) { + if (0 == strcmp(tm->tag_name, t)) { + *passthrough = tm->tag_passthrough; + return tm->tag_type; + } + } + *passthrough = 1; + return tt_unknown; +} + +static void +tag_gpx(const char **attrv) +{ + const char **avp = &attrv[0]; + while (*avp) { + if (strcmp(avp[0], "version") == 0) { + gpx_version = avp[1]; + } + else if (strcmp(avp[0], "src") == 0) { + gpx_creator = avp[1]; + } + else if (strcmp(avp[0], "xsi:schemaLocation") == 0) { + if (0 == strstr(xsi_schema_loc, avp[1])) { + xsi_schema_loc = xstrappend(xsi_schema_loc, " "); + xsi_schema_loc = xstrappend(xsi_schema_loc, avp[1]); + } + } + avp+=2; + } +} + +static void +tag_wpt(const char **attrv) +{ + const char **avp = &attrv[0]; + + wpt_tmp = waypt_new(); + + cur_tag = NULL; + while (*avp) { + if (strcmp(avp[0], "lat") == 0) { + sscanf(avp[1], "%lf", + &wpt_tmp->latitude); + } + else if (strcmp(avp[0], "lon") == 0) { + sscanf(avp[1], "%lf", + &wpt_tmp->longitude); + } + avp+=2; + } +} + +static void +tag_cache_desc(const char ** attrv) +{ + const char **avp; + + cache_descr_is_html = 0; + for (avp = &attrv[0]; *avp; avp+=2) { + if (strcmp(avp[0], "html") == 0) { + if (strcmp(avp[1], "True") == 0) { + cache_descr_is_html = 1; + } + } + } +} + +static void +tag_gs_cache(const char **attrv) +{ + const char **avp; + + cache_descr_is_html = 0; + for (avp = &attrv[0]; *avp; avp+=2) { + if (strcmp(avp[0], "id") == 0) { + wpt_tmp->gc_data.id = atoi(avp[1]); + } + } +} + +static void +start_something_else(const char *el, const char **attrv) +{ + const char **avp = attrv; + char **avcp = NULL; + int attr_count = 0; + xml_tag *new_tag; + + if ( !wpt_tmp ) { + return; + } + + new_tag = (xml_tag *)xcalloc(sizeof(xml_tag),1); + new_tag->tagname = xstrdup(el); + + /* count attributes */ + while (*avp) { + attr_count++; + avp++; + } + + /* copy attributes */ + avp = attrv; + new_tag->attributes = (char **)xcalloc(sizeof(char *),attr_count+1); + avcp = new_tag->attributes; + while (*avp) { + *avcp = xstrdup(*avp); + avcp++; + avp++; + } + *avcp = NULL; + + if ( cur_tag ) { + if ( cur_tag->child ) { + cur_tag = cur_tag->child; + while ( cur_tag->sibling ) { + cur_tag = cur_tag->sibling; + } + cur_tag->sibling = new_tag; + new_tag->parent = cur_tag->parent; + } + else { + cur_tag->child = new_tag; + new_tag->parent = cur_tag; + } + } + else { + if ( wpt_tmp->gpx_extras ) { + cur_tag = wpt_tmp->gpx_extras; + while ( cur_tag->sibling ) { + cur_tag = cur_tag->sibling; + } + cur_tag->sibling = new_tag; + new_tag->parent = NULL; + } + else { + wpt_tmp->gpx_extras = new_tag; + new_tag->parent = NULL; + } + } + cur_tag = new_tag; +} + +static void +end_something_else() +{ + if ( cur_tag ) { + cur_tag = cur_tag->parent; + } +} + +static void +tag_log_wpt(const char **attrv) +{ + waypoint * lwp_tmp; + const char **avp = &attrv[0]; + + /* create a new waypoint */ + lwp_tmp = waypt_new(); + + /* extract the lat/lon attributes */ + while (*avp) { + if (strcmp(avp[0], "lat") == 0) { + sscanf(avp[1], "%lf", + &lwp_tmp->latitude); + } + else if (strcmp(avp[0], "lon") == 0) { + sscanf(avp[1], "%lf", + &lwp_tmp->longitude); + } + avp+=2; + } + /* Make a new shortname. Since this is a groundspeak extension, + we assume that GCBLAH is the current shortname format and that + wpt_tmp refers to the currently parsed waypoint. Unfortunatley, + we need to keep track of log_wpt counts so we don't collide with + dupe shortnames. + */ + + if ((wpt_tmp->shortname) && (strlen(wpt_tmp->shortname) > 2)) { + /* copy of the shortname */ + lwp_tmp->shortname = xcalloc(7, 1); + sprintf(lwp_tmp->shortname, "%-4.4s%02d", + &wpt_tmp->shortname[2], logpoint_ct++); + + waypt_add(lwp_tmp); + } +} + +static void +gpx_start(void *data, const char *el, const char **attr) +{ + char *e; + char *ep; + int passthrough; + + vmem_realloc(¤t_tag, strlen(current_tag.mem) + 2 + strlen(el)); + e = current_tag.mem; + ep = e + strlen(e); + *ep++ = '/'; + strcpy(ep, el); + + + /* + * FIXME: Find out why a cdatastr[0] doesn't adequately reset the + * cdata handler. + */ + memset(cdatastr.mem, 0, cdatastr.size); + + switch (get_tag(current_tag.mem, &passthrough)) { + case tt_gpx: + tag_gpx(attr); + break; + case tt_wpt: + tag_wpt(attr); + break; + case tt_rte: + rte_head = route_head_alloc(); + route_add_head(rte_head); + break; + case tt_rte_rtept: + tag_wpt(attr); + break; + case tt_trk: + trk_head = route_head_alloc(); + track_add_head(trk_head); + break; + case tt_trk_trkseg_trkpt: + tag_wpt(attr); + break; + case tt_unknown: + start_something_else(el, attr); + return; + case tt_cache: + tag_gs_cache(attr); + break; + case tt_cache_log_wpt: + if (opt_logpoint) + tag_log_wpt(attr); + break; + case tt_cache_desc_long: + case tt_cache_desc_short: + tag_cache_desc(attr); + break; + default: + break; + } + if (passthrough) { + start_something_else(el, attr); + } +} + +struct +gs_type_mapping{ + geocache_type type; + const char *name; +} gs_type_map[] = { + { gt_traditional, "Traditional cache" }, + { gt_multi, "Multi-Cache" }, + { gt_virtual, "Virtual cache" }, + { gt_event, "Event cache" }, + { gt_webcam, "Webcam Cache" }, + { gt_suprise, "Unknown cache" }, +}; + +struct +gs_container_mapping{ + geocache_container type; + const char *name; +} gs_container_map[] = { + { gc_other, "Unknown" }, + { gc_micro, "Micro" }, + { gc_regular, "Regular" }, + { gc_large, "Large" }, + { gc_small, "Small" }, + { gc_virtual, "Virtual" } +}; + +geocache_type +gs_mktype(char *t) +{ + int i; + int sz = sizeof(gs_type_map) / sizeof(gs_type_map[0]); + + for (i = 0; i < sz; i++) { + if (0 == case_ignore_strcmp(t, gs_type_map[i].name)) { + return gs_type_map[i].type; + } + } + return gt_unknown; +} + +const char * +gs_get_cachetype(geocache_type t) +{ + int i; + int sz = sizeof(gs_type_map) / sizeof(gs_type_map[0]); + + for (i = 0; i < sz; i++) { + if (t == gs_type_map[i].type) { + return gs_type_map[i].name; + } + } + return "Unknown"; +} + +geocache_container +gs_mkcont(char *t) +{ + int i; + int sz = sizeof(gs_container_map) / sizeof(gs_container_map[0]); + + for (i = 0; i < sz; i++) { + if (0 == case_ignore_strcmp(t, gs_container_map[i].name)) { + return gs_container_map[i].type; + } + } + return gc_unknown; +} + +const char * +gs_get_container(geocache_container t) +{ + int i; + int sz = sizeof(gs_container_map) / sizeof(gs_container_map[0]); + + for (i = 0; i < sz; i++) { + if (t == gs_container_map[i].type) { + return gs_container_map[i].name; + } + } + return "Unknown"; +} + +time_t +xml_parse_time( char *cdatastr ) +{ + int off_hr = 0; + int off_min = 0; + int off_sign = 1; + char *offsetstr = NULL; + char *pointstr = NULL; + struct tm tm; + time_t rv = 0; + char *timestr = xstrdup( cdatastr ); + + offsetstr = strchr( timestr, 'Z' ); + if ( offsetstr ) { + /* zulu time; offsets stay at defaults */ + *offsetstr = '\0'; + } else { + offsetstr = strchr( timestr, '+' ); + if ( offsetstr ) { + /* positive offset; parse it */ + *offsetstr = '\0'; + sscanf( offsetstr+1, "%d:%d", &off_hr, &off_min ); + } else { + offsetstr = strchr( timestr, 'T' ); + if ( offsetstr ) { + offsetstr = strchr( offsetstr, '-' ); + if ( offsetstr ) { + /* negative offset; parse it */ + *offsetstr = '\0'; + sscanf( offsetstr+1, "%d:%d", + &off_hr, &off_min ); + off_sign = -1; + } + } + } + } + + pointstr = strchr( timestr, '.' ); + if ( pointstr ) { + *pointstr = '\0'; + } + + sscanf(timestr, "%d-%d-%dT%d:%d:%d", + &tm.tm_year, + &tm.tm_mon, + &tm.tm_mday, + &tm.tm_hour, + &tm.tm_min, + &tm.tm_sec); + tm.tm_mon -= 1; + tm.tm_year -= 1900; + tm.tm_isdst = 0; + + rv = mktime(&tm) + get_tz_offset() - off_sign*off_hr*3600 - + off_sign*off_min*60; + + xfree(timestr); + + return rv; +} + +static void +gpx_end(void *data, const char *el) +{ + char *s = strrchr(current_tag.mem, '/'); + float x; + char *cdatastrp = cdatastr.mem; + int passthrough; + + if (strcmp(s + 1, el)) { + fprintf(stderr, "Mismatched tag %s\n", el); + } + + switch (get_tag(current_tag.mem, &passthrough)) { + /* + * First, the tags that are file-global. + */ + case tt_time: + file_time = xml_parse_time(cdatastrp); + break; + case tt_email: + if (gpx_email) xfree(gpx_email); + gpx_email = xstrdup(cdatastrp); + break; + case tt_author: + if (gpx_author) xfree(gpx_author); + gpx_author = xstrdup(cdatastrp); + break; + case tt_gpx: + /* Could invoke release code here */ + break; + /* + * Waypoint-specific tags. + */ + case tt_wpt_url: + wpt_tmp->url = xstrdup(cdatastrp); + break; + case tt_wpt_urlname: + wpt_tmp->url_link_text = xstrdup(cdatastrp); + break; + case tt_wpt: + waypt_add(wpt_tmp); + logpoint_ct = 0; + cur_tag = NULL; + wpt_tmp = NULL; + break; + case tt_cache_name: + if (gsshortnames) { + if (wpt_tmp->notes) + xfree(wpt_tmp->notes); + wpt_tmp->notes = xstrdup(cdatastrp); + } + break; + case tt_cache_container: + wpt_tmp->gc_data.container = gs_mkcont(cdatastrp); + break; + case tt_cache_type: + wpt_tmp->gc_data.type = gs_mktype(cdatastrp); + break; + case tt_cache_difficulty: + sscanf(cdatastrp, "%f", &x); + wpt_tmp->gc_data.diff = x * 10; + break; + case tt_cache_hint: + rtrim(cdatastrp); + if (cdatastrp[0]) { + wpt_tmp->gc_data.hint = xstrdup(cdatastrp); + } + break; + case tt_cache_desc_long: + rtrim(cdatastrp); + if (cdatastrp[0]) { + wpt_tmp->gc_data.desc_long.is_html = cache_descr_is_html; + wpt_tmp->gc_data.desc_long.utfstring = xstrdup(cdatastrp); + } + break; + case tt_cache_desc_short: + rtrim(cdatastrp); + if (cdatastrp[0]) { + wpt_tmp->gc_data.desc_short.is_html = cache_descr_is_html; + wpt_tmp->gc_data.desc_short.utfstring = xstrdup(cdatastrp); + } + break; + case tt_cache_terrain: + sscanf(cdatastrp, "%f", &x); + wpt_tmp->gc_data.terr = x * 10; + break; + /* + * Route-specific tags. + */ + case tt_rte_name: + rte_head->rte_name = xstrdup(cdatastrp); + break; + case tt_rte: + break; + case tt_rte_rtept: + route_add_wpt(rte_head, wpt_tmp); + break; + case tt_rte_desc: + rte_head->rte_desc = xstrdup(cdatastrp); + break; + case tt_rte_number: + rte_head->rte_num = atoi(cdatastrp); + break; + /* + * Track-specific tags. + */ + case tt_trk_name: + trk_head->rte_name = xstrdup(cdatastrp); + break; + case tt_trk: + break; + case tt_trk_trkseg_trkpt: + route_add_wpt(trk_head, wpt_tmp); + break; + case tt_trk_desc: + trk_head->rte_desc = xstrdup(cdatastrp); + break; + case tt_trk_number: + trk_head->rte_num = atoi(cdatastrp); + break; + + /* + * Items that are actually in multiple categories. + */ + case tt_wpt_ele: + case tt_rte_rtept_ele: + case tt_trk_trkseg_trkpt_ele: + sscanf(cdatastrp, "%lf", &wpt_tmp->altitude); + break; + case tt_wpt_name: + case tt_rte_rtept_name: + case tt_trk_trkseg_trkpt_name: + wpt_tmp->shortname = xstrdup(cdatastrp); + break; + case tt_wpt_sym: + case tt_rte_rtept_sym: + case tt_trk_trkseg_trkpt_sym: + wpt_tmp->icon_descr = xstrdup(cdatastrp); + wpt_tmp->icon_descr_is_dynamic = 1; + break; + case tt_wpt_time: + case tt_trk_trkseg_trkpt_time: + case tt_rte_rtept_time: + wpt_tmp->creation_time = xml_parse_time( cdatastrp ); + break; + case tt_wpt_cmt: + case tt_rte_rtept_cmt: + case tt_trk_trkseg_trkpt_cmt: + wpt_tmp->description = xstrdup(cdatastrp); + break; + case tt_wpt_desc: + case tt_trk_trkseg_trkpt_desc: + case tt_rte_rtept_desc: + wpt_tmp->notes = xstrdup(cdatastrp); + break; + case tt_unknown: + end_something_else(); + *s = 0; + return; + default: + break; + } + + if (passthrough) + end_something_else(); + + *s = 0; +} + +#if NO_EXPAT +void +gpx_rd_init(const char *fname) +{ + fatal(MYNAME ": This build excluded GPX support because expat was not installed.\n"); +} + +#else /* NO_EXPAT */ + +static void +gpx_cdata(void *dta, const XML_Char *s, int len) +{ + char *estr; + int *cdatalen; + char **cdata; + xml_tag *tmp_tag; + + vmem_realloc(&cdatastr, 1 + len + strlen(cdatastr.mem)); + estr = (char *) cdatastr.mem + strlen(cdatastr.mem); + memcpy(estr, s, len); + estr[len] = 0; + + if (!cur_tag) + return; + + if ( cur_tag->child ) { + tmp_tag = cur_tag->child; + while ( tmp_tag->sibling ) { + tmp_tag = tmp_tag->sibling; + } + cdata = &(tmp_tag->parentcdata); + cdatalen = &(tmp_tag->parentcdatalen); + } + else { + cdata = &(cur_tag->cdata); + cdatalen = &(cur_tag->cdatalen); + } + estr = *cdata; + *cdata = xcalloc( *cdatalen + len + 1, 1); + if ( estr ) { + memcpy( *cdata, estr, *cdatalen); + xfree( estr ); + } + estr = *cdata + *cdatalen; + memcpy( estr, s, len ); + *(estr+len) = '\0'; + *cdatalen += len; +} + +void +gpx_rd_init(const char *fname) +{ + if ( fname[0] ) { + fd = xfopen(fname, "r", MYNAME); + } + else { + fd = NULL; + input_string = fname+1; + input_string_len = strlen(input_string); + } + + + file_time = 0; + current_tag = vmem_alloc(1, 0); + *((char *)current_tag.mem) = '\0'; + + psr = XML_ParserCreate(NULL); + if (!psr) { + fatal(MYNAME ": Cannot create XML Parser\n"); + } + cdatastr = vmem_alloc(1, 0); + *((char *)cdatastr.mem) = '\0'; + + /* We don't use xstrdup here because we' know we don't free + * this across reads and we unlock the safety belt from the + * leak tester. + */ + if (!xsi_schema_loc) { + xsi_schema_loc = strdup(DEFAULT_XSI_SCHEMA_LOC); + } + if (!xsi_schema_loc) { + fatal("gpx: Unable to allocate %d bytes of memory.\n", strlen(DEFAULT_XSI_SCHEMA_LOC) + 1); + } + + XML_SetElementHandler(psr, gpx_start, gpx_end); + XML_SetCharacterDataHandler(psr, gpx_cdata); +} +#endif + +static +void +gpx_rd_deinit(void) +{ + vmem_free(¤t_tag); + vmem_free(&cdatastr); + /* + * Don't free schema_loc. It really is important that we preserve + * this across reads or else merges/copies of files with different + * schemas won't retain the headers. + * + if ( xsi_schema_loc ) { + xfree(xsi_schema_loc); + xsi_schema_loc = NULL; + } + */ + if ( gpx_email ) { + xfree(gpx_email); + gpx_email = NULL; + } + if ( gpx_author ) { + xfree(gpx_author); + gpx_author = NULL; + } + if (fd) { + fclose(fd); + } + XML_ParserFree(psr); + psr = NULL; +} + +void +gpx_wr_init(const char *fname) +{ + mkshort_handle = mkshort_new_handle(); + + ofd = xfopen(fname, "w", MYNAME); +} + +static void +gpx_wr_deinit(void) +{ + fclose(ofd); + mkshort_del_handle(mkshort_handle); +} + +void +gpx_read(void) +{ +#ifndef NO_EXPAT + int len; + int done = 0; + char buf[MY_CBUF]; + int result = 0; + + while (!done) { + if ( fd ) { + /* + * The majority of this block (in fact, all but the + * call to XML_Parse) are a disgusting hack to + * correct defective GPX files that Geocaching.com + * issues as pocket queries. They contain escape + * characters as entities (�-) which makes + * them not validate which croaks expat and torments + * users. + * + * Look for '&' in the last 6 chars. If we find + * it, strip it, then read byte-at-a-time until + * we find a non-entity. + */ + char *badchar; + char *semi; + len = fread(buf, 1, sizeof(buf)-7, fd); + done = feof(fd) || !len; + buf[len] = '\0'; + badchar = buf+len-7; + badchar = strchr( badchar, '&' ); + while ( badchar ) { + int extra = 7; + semi = strchr( badchar, ';'); + while ( extra && !semi ) { + len += fread( buf+len, 1, 1, fd); + buf[len]='\0'; + extra--; + if ( buf[len-1] == ';') + semi= buf+len-1; + } + badchar = strchr( badchar+1, '&' ); + } + { + char *hex="0123456789abcdef"; + badchar = strstr( buf, "&#x" ); + while ( badchar ) { + int val = 0; + char *hexit = badchar+3; + semi = strchr( badchar, ';' ); + if ( semi ) { + while (*hexit && *hexit != ';') { + val *= 16; + val += strchr( hex, *hexit )-hex; + hexit++; + } + + if ( val < 32 ) { + warning( MYNAME ": Ignoring illegal character %s;\n\tConsider emailing %s at <%s>\n\tabout illegal characters in their GPX files.\n", badchar, gpx_author?gpx_author:"(unknown author)", gpx_email?gpx_email:"(unknown email address)" ); + memmove( badchar, semi+1, strlen(semi+1)+1 ); + len -= (semi-badchar)+1; + badchar--; + } + } + badchar = strstr( badchar+1, "&#x" ); + } + } + result = XML_Parse(psr, buf, len, done); + } + else if (input_string) { + done = 0; + result = XML_Parse(psr, input_string, + input_string_len, done ); + done = 1; + } + else { + done = 1; + result = -1; + } + if (!result) { + fatal(MYNAME ": XML parse error at %d: %s\n", + XML_GetCurrentLineNumber(psr), + XML_ErrorString(XML_GetErrorCode(psr))); + } + } +#endif /* NO_EXPAT */ +} + +/* + * + */ +static +void +gpx_write_time(const time_t timep, char *elname) +{ + struct tm *tm = gmtime(&timep); + + if (!tm) + return; + + fprintf(ofd, "<%s>%02d-%02d-%02dT%02d:%02d:%02dZ\n", + elname, + tm->tm_year+1900, + tm->tm_mon+1, + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec, + elname + ); + +} + +static void +fprint_tag_and_attrs( char *prefix, char *suffix, xml_tag *tag ) +{ + char **pa; + fprintf( ofd, "%s%s", prefix, tag->tagname ); + pa = tag->attributes; + if ( pa ) { + while ( *pa ) { + fprintf( ofd, " %s=\"%s\"", pa[0], pa[1] ); + pa += 2; + } + } + fprintf( ofd, "%s", suffix ); +} + +static void +fprint_xml_chain( xml_tag *tag, const waypoint *wpt ) +{ + char *tmp_ent; + while ( tag ) { + if ( !tag->cdata && !tag->child ) { + fprint_tag_and_attrs( "<", " />", tag ); + } + else { + fprint_tag_and_attrs( "<", ">", tag ); + + if ( tag->cdata ) { + tmp_ent = xml_entitize( tag->cdata ); + fprintf( ofd, "%s", tmp_ent ); + xfree(tmp_ent); + } + if ( tag->child ) { + fprint_xml_chain(tag->child, wpt); + } + if ( strcmp(tag->tagname, "groundspeak:cache" ) == 0 + && wpt->gc_data.exported) { + gpx_write_time( wpt->gc_data.exported, + "groundspeak:exported" ); + } + fprintf( ofd, "", tag->tagname); + } + if ( tag->parentcdata ) { + tmp_ent = xml_entitize(tag->parentcdata); + fprintf(ofd, "%s", tmp_ent ); + xfree(tmp_ent); + } + tag = tag->sibling; + } +} + +void free_gpx_extras( xml_tag *tag ) +{ + xml_tag *next = NULL; + char **ap; + + while ( tag ) { + if (tag->cdata) { + xfree(tag->cdata); + } + if (tag->child) { + free_gpx_extras(tag->child); + } + if (tag->parentcdata) { + xfree(tag->parentcdata); + } + if (tag->tagname) { + xfree(tag->tagname); + } + if (tag->attributes) { + ap = tag->attributes; + + while (*ap) + xfree(*ap++); + + xfree(tag->attributes); + } + + next = tag->sibling; + xfree(tag); + tag = next; + } +} + +static void +gpx_waypt_pr(const waypoint *waypointp) +{ + char *tmp_ent; + const char *oname; + char *odesc; + + /* + * Desparation time, try very hard to get a good shortname + */ + odesc = waypointp->notes; + if (!odesc) { + odesc = waypointp->description; + } + if (!odesc) { + odesc = waypointp->shortname; + } + + oname = global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, odesc) : + waypointp->shortname; + + fprintf(ofd, "\n", + waypointp->latitude, + waypointp->longitude); + if (waypointp->creation_time) { + gpx_write_time(waypointp->creation_time, "time"); + } + if (waypointp->altitude != unknown_alt) { + fprintf(ofd, " %f\n", + waypointp->altitude); + } + write_optional_xml_entity(ofd, " ", "name", oname); + write_optional_xml_entity(ofd, " ", "cmt", waypointp->description); + if (waypointp->notes && waypointp->notes[0]) + write_xml_entity(ofd, " ", "desc", waypointp->notes); + else + write_optional_xml_entity(ofd, " ", "desc", waypointp->description); + if (waypointp->url) { + tmp_ent = xml_entitize(waypointp->url); + fprintf(ofd, " %s%s\n", urlbase ? urlbase : "", tmp_ent); + xfree(tmp_ent); + } + write_optional_xml_entity(ofd, " ", "urlname", waypointp->url_link_text); + write_optional_xml_entity(ofd, " ", "sym", waypointp->icon_descr); + + fprint_xml_chain( waypointp->gpx_extras, waypointp ); + fprintf(ofd, "\n"); +} + +static void +gpx_track_hdr(const route_head *rte) +{ + fprintf(ofd, "\n"); + write_optional_xml_entity(ofd, " ", "name", rte->rte_name); + write_optional_xml_entity(ofd, " ", "desc", rte->rte_desc); + if (rte->rte_num) { + fprintf(ofd, "%d\n", rte->rte_num); + } + fprintf(ofd, "\n"); +} + +static void +gpx_track_disp(const waypoint *waypointp) +{ + fprintf(ofd, "\n", + waypointp->latitude, + waypointp->longitude); + if (waypointp->altitude != unknown_alt) { + fprintf(ofd, "%f\n", + waypointp->altitude); + } + if (waypointp->creation_time) { + gpx_write_time(waypointp->creation_time,"time"); + } + fprintf(ofd, "\n"); +} + +static void +gpx_track_tlr(const route_head *rte) +{ + fprintf(ofd, "\n"); + fprintf(ofd, "\n"); +} + +static +void gpx_track_pr() +{ + track_disp_all(gpx_track_hdr, gpx_track_tlr, gpx_track_disp); +} + +static void +gpx_route_hdr(const route_head *rte) +{ + fprintf(ofd, "\n"); + write_optional_xml_entity(ofd, " ", "name", rte->rte_name); + write_optional_xml_entity(ofd, " ", "desc", rte->rte_desc); + if (rte->rte_num) { + fprintf(ofd, " %d\n", rte->rte_num); + } +} + +static void +gpx_route_disp(const waypoint *waypointp) +{ + fprintf(ofd, " \n", + waypointp->latitude, + waypointp->longitude); + + if (waypointp->altitude != unknown_alt) { + fprintf(ofd, " %f\n", + waypointp->altitude); + } + if (waypointp->creation_time) { + gpx_write_time(waypointp->creation_time,"time"); + } + write_optional_xml_entity(ofd, " ", "name", waypointp->shortname); + write_optional_xml_entity(ofd, " ", "cmt", waypointp->description); + write_optional_xml_entity(ofd, " ", "desc", waypointp->notes); + write_optional_xml_entity(ofd, " ", "sym", waypointp->icon_descr); + fprintf(ofd, " \n"); +} + +static void +gpx_route_tlr(const route_head *rte) +{ + fprintf(ofd, "\n"); +} + +static +void gpx_route_pr() +{ + /* output routes */ + route_disp_all(gpx_route_hdr, gpx_route_tlr, gpx_route_disp); +} + +void +gpx_write(void) +{ + time_t now = 0; + int short_length; + bounds bounds; + + now = current_time(); + + if (snlen) + short_length = atoi(snlen); + else + short_length = 32; + + if (suppresswhite) { + setshort_whitespace_ok(mkshort_handle, 0); + } + + setshort_length(mkshort_handle, short_length); + + fprintf(ofd, "\n"); + fprintf(ofd, "\n", xsi_schema_loc ? xsi_schema_loc : DEFAULT_XSI_SCHEMA_LOC); + + gpx_write_time( now, "time" ); + waypt_compute_bounds(&bounds); + if (bounds.max_lat > -360) { + fprintf(ofd, "\n", + bounds.min_lat, bounds.min_lon, + bounds.max_lat, bounds.max_lon); + } + waypt_disp_all(gpx_waypt_pr); + gpx_track_pr(); + gpx_route_pr(); + + fprintf(ofd, "\n"); +} + +static +arglist_t gpx_args[] = { + { "gsshortnames", &gsshortnames, + "Prefer shorter descriptions from Groundspeak files", + NULL, ARGTYPE_BOOL }, + { "snlen", &snlen, "Length of generated shortnames", + NULL, ARGTYPE_INT }, + { "suppresswhite", &suppresswhite, + "Suppress whitespace in generated shortnames", + NULL, ARGTYPE_BOOL }, + { "logpoint", &opt_logpoint, + "Create waypoints from geocache log entries", + NULL, ARGTYPE_BOOL }, + { "urlbase", &urlbase, "Base URL for link tag in output", + NULL, ARGTYPE_STRING}, + { 0, 0, 0, 0, 0 } +}; + +ff_vecs_t gpx_vecs = { + ff_type_file, + gpx_rd_init, + gpx_wr_init, + gpx_rd_deinit, + gpx_wr_deinit, + gpx_read, + gpx_write, + NULL, + gpx_args, +}; diff --git a/gpxval b/gpxval new file mode 100644 index 000000000..2447c1d2f --- /dev/null +++ b/gpxval @@ -0,0 +1,8 @@ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/robertl/xerces-c1_7_0-linux7.2/lib +export PATH=$PATH:/home/robertl/xerces-c1_7_0-linux7.2/bin + +SAX2Count reference/holux.gpx +./gpsbabel -i gpx -f reference/holux.gpx -o gpx -F /tmp/1.gpx +SAX2Count /tmp/1.gpx +./gpsbabel -i mapsend -f reference/chicago.trk -o gpx -F /tmp/2.gpx +SAX2Count /tmp/2.gpx diff --git a/grtcirc.c b/grtcirc.c new file mode 100644 index 000000000..d5e5cddbb --- /dev/null +++ b/grtcirc.c @@ -0,0 +1,205 @@ +/* + Great Circle utility functions + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include +#include "defs.h" + +static void crossproduct( double x1, double y1, double z1, + double x2, double y2, double z2, + double *xa, double *ya, double *za ) { + *xa = y1*z2-y2*z1; + *ya = z1*x2-z2*x1; + *za = x1*y2-y1*x2; +} + +static double dotproduct( double x1, double y1, double z1, + double x2, double y2, double z2 ) { + return (x1*x2+y1*y2+z1*z2); +} + +/* + * Note: this conversion to miles uses the WGS84 value for the radius of + * the earth at the equator. + * (radius in meters)*(100cm/m) -> (radius in cm) + * (radius in cm) / (2.54 cm/in) -> (radius in in) + * (radius in in) / (12 in/ft) -> (radius in ft) + * (radius in ft) / (5280 ft/mi) -> (radius in mi) + * If the compiler is half-decent, it'll do all the math for us at compile + * time, so why not leave the expression human-readable? + */ + +double tomiles( double rads ) { + const double radmiles = 6378137.0*100.0/2.54/12.0/5280.0; + return (rads*radmiles); +} + +double gcdist( double lat1, double lon1, double lat2, double lon2 ) { + return acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon1-lon2)); +} + +double linedist(double lat1, double lon1, + double lat2, double lon2, + double lat3, double lon3 ) { + + static double _lat1 = -9999; + static double _lat2 = -9999; + static double _lon1 = -9999; + static double _lon2 = -9999; + + static double x1,y1,z1; + static double x2,y2,z2; + static double xa,ya,za,la; + + double x3,y3,z3; + double xp,yp,zp,lp; + + double xa1,ya1,za1; + double xa2,ya2,za2; + + double d1, d2; + double c1, c2; + + double dot; + + int newpoints; + + /* degrees to radians */ + lat1 *= M_PI/180.0; lon1 *= M_PI/180.0; + lat2 *= M_PI/180.0; lon2 *= M_PI/180.0; + lat3 *= M_PI/180.0; lon3 *= M_PI/180.0; + + newpoints = 1; + if ( lat1 == _lat1 && lat2 == _lat2 && lon1 == _lon1 && lon2 == _lon2) { + newpoints = 0; + } + else { + _lat1 = lat1; + _lat2 = lat2; + _lon1 = lon1; + _lon2 = lon2; + } + + /* polar to ECEF rectangular */ + if ( newpoints ) { + x1 = cos(lon1)*cos(lat1); y1 = sin(lat1); z1 = sin(lon1)*cos(lat1); + x2 = cos(lon2)*cos(lat2); y2 = sin(lat2); z2 = sin(lon2)*cos(lat2); + } + x3 = cos(lon3)*cos(lat3); y3 = sin(lat3); z3 = sin(lon3)*cos(lat3); + + if ( newpoints ) { + /* 'a' is the axis; the line that passes through the center of the earth + * and is perpendicular to the great circle through point 1 and point 2 + * It is computed by taking the cross product of the '1' and '2' vectors.*/ + crossproduct( x1, y1, z1, x2, y2, z2, &xa, &ya, &za ); + la = sqrt(xa*xa+ya*ya+za*za); + + if ( la ) { + xa /= la; + ya /= la; + za /= la; + } + } + if ( la ) { + + /* dot is the component of the length of '3' that is along the axis. + * What's left is a non-normalized vector that lies in the plane of + * 1 and 2. */ + + dot = dotproduct(x3,y3,z3,xa,ya,za); + + xp = x3-dot*xa; + yp = y3-dot*ya; + zp = z3-dot*za; + + lp = sqrt(xp*xp+yp*yp+zp*zp); + + if ( lp ) { + + /* After this, 'p' is normalized */ + xp /= lp; + yp /= lp; + zp /= lp; + + crossproduct(x1,y1,z1,xp,yp,zp,&xa1,&ya1,&za1); + d1 = dotproduct( xa1, ya1, za1, xa, ya, za ); + + crossproduct(xp,yp,zp,x2,y2,z2,&xa2,&ya2,&za2); + d2 = dotproduct( xa2, ya2, za2, xa, ya, za ); + + if ( d1 >= 0 && d2 >= 0 ) { + /* rather than call gcdist and all its sines and cosines and + * worse, we can get the angle directly. It's the arctangent + * of the length of the component of vector 3 along the axis + * divided by the length of the component of vector 3 in the + * plane. We already have both of those numbers. + * + * atan2 would be overkill because lp and fabs(dot) are both + * known to be positive. */ + + return atan( fabs(dot)/lp ); + } + + /* otherwise, get the distance from the closest endpoint */ + c1 = dotproduct( x1,y1,z1,xp,yp,zp ); + c2 = dotproduct( x2,y2,z2,xp,yp,zp ); + d1 = fabs(d1); + d2 = fabs(d2); + + /* This is a hack. d$n$ is proportional to the sine of the angle + * between point $n$ and point p. That preserves orderedness up + * to an angle of 90 degrees. c$n$ is proportional to the cosine + * of the same angle; if the angle is over 90 degrees, c$n$ is + * negative. In that case, we flop the sine across the y=1 axis + * so that the resulting value increases as the angle increases. + * + * This only works because all of the points are on a unit sphere. */ + + if ( c1 < 0 ) { + d1 = 2 - d1; + } + if ( c2 < 0 ) { + d2 = 2 - d2; + } + + if ( fabs(d1) < fabs(d2)) { + return gcdist(lat1,lon1,lat3,lon3); + } + else { + return gcdist(lat2,lon2,lat3,lon3); + } + } + else { + /* lp is 0 when 3 is 90 degrees from the great circle */ + return M_PI/2; + } + } + else { + /* la is 0 when 1 and 2 are either the same point or 180 degrees apart */ + dot = dotproduct(x1,y1,z1,x2,y2,z2); + if ( dot >= 0 ) { + return gcdist(lat1,lon1,lat3,lon3); + } + else { + return 0; + } + } + return 0; +} + diff --git a/grtcirc.h b/grtcirc.h new file mode 100644 index 000000000..de84aea4c --- /dev/null +++ b/grtcirc.h @@ -0,0 +1,27 @@ +/* + Great Circle utility functions + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +double gcdist( double lat1, double lon1, double lat2, double lon2 ); + +double linedist(double lat1, double lon1, + double lat2, double lon2, + double lat3, double lon3 ); + +double tomiles( double rads ); diff --git a/guibabel b/guibabel new file mode 100644 index 000000000..d0197df23 --- /dev/null +++ b/guibabel @@ -0,0 +1,99 @@ +#!/bin/sh +# the next line restarts using wish \ +exec wish "$0" "$@" + +# +# This was largely cribbed from the TCL demo code. My TCL skills weren't +# that great when I last used it about ten years ago and my Tk skills never +# existed before. So be kind. +# + +set font {Helvetica 14} +set ifile {} +set ofile {} +set use_shortnames 0 + +proc positionWindow w { + wm geometry $w +300+300 +} + +proc showCmd w { + global ifile ofile use_shortnames ftyperead ftypewrite + set cmd "gpsbabel -i $ftyperead -f $ifile" + if {$use_shortnames > 0} { + set cmd [concat $cmd "-s"] + } + set cmd [concat $cmd "-o $ftypewrite -F $ofile"] + eval exec $cmd + +# tk_messageBox -icon info -message $cmd +} + +set w .filebox +catch {destroy $w} +toplevel $w +wm title $w "gpsbabel" +wm iconname $w "filebox" +positionWindow $w + +#label $w.msg -font $font -wraplength 4i -justify left -text "Enter a file name in the entry box or click on the \"Browse\" buttons to select a file name using the file selection dialog." +#pack $w.msg -side top + +frame $w.buttons +pack $w.buttons -side bottom -fill x -pady 2m +button $w.buttons.dismiss -text End -command "destroy $w" +button $w.buttons.code -text OK -command "showCmd $w" +pack $w.buttons.dismiss $w.buttons.code -side left -expand 1 + +foreach i {read write} { + set f [frame $w.$i] + set ftype "ftype$i" + label $f.lab -text "Select a file to $i: " -anchor e + entry $f.ent -width 20 + button $f.but -text "Browse ..." -command "fileDialog $w $f.ent $i" +# TODO: Get this list from 'gpsbabel -?' instead of hardcoding it here. + tk_optionMenu $f.ftypes $ftype geo gpsman gpx \ + magellan mapsend pcx mapsource gpsutil tiger csv xmap dna psp \ + cetus gpspilot magnav garmin mxf holux ozi tpg igc baroiq + pack $f.lab -side left + pack $f.ent -side left -expand yes -fill x + pack $f.but -side left + pack $f -fill x -padx 1c -pady 3 + pack $f.ftypes -side right -padx 45 +} +set ftyperead "geo" +set ftypewrite "mapsend" + + checkbutton $w.strict -text "Make Up Shortnames" \ + -variable use_shortnames -onvalue 1 -offvalue 0 + pack $w.strict -anchor c + +proc fileDialog {w ent operation} { + # Type names Extension(s) Mac File Type(s) + # + #--------------------------------------------------------- + set types { + {"All files" * } + {"loc files" {.loc} } + {"Waypoint files" {.wpt} } + {"GPX files" {.gpx} } + {"Various Palm/OS files" {.pdb} } + } + global ifile ofile + if {$operation == "read"} { + set ifile [tk_getOpenFile -filetypes $types -parent $w] + if [string compare $ifile ""] { + $ent delete 0 end + $ent insert 0 $ifile + $ent xview end + } ; + } else { + set ofile [tk_getSaveFile -filetypes $types -parent $w \ + -initialfile Untitled ] + if [string compare $ofile ""] { + $ent delete 0 end + $ent insert 0 $ofile + $ent xview end + } ; + } +} diff --git a/holux.c b/holux.c new file mode 100644 index 000000000..41735b2d4 --- /dev/null +++ b/holux.c @@ -0,0 +1,301 @@ +/* + Access to holux wpo files. + + Copyright (C) 2002 Jochen Becker, jb@bepo.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + +History: + 2002-09-15 J. Becker start programming + + +*/ +/* This module is for the holux (gm-100) .wpo format */ + + + +#include +#include "defs.h" +#include "holux.h" + + +static FILE *file_in; +static unsigned char *HxWFile; +static void *mkshort_handle; +static char fOutname[256]; +#define MYNAME "Holux" + + +static void rd_init(const char *fname) +{ + file_in = xfopen(fname, "rb", MYNAME); +} + + +static void rd_deinit(void) +{ + fclose(file_in); +} + + + + + +static void +wr_init(const char *fname) +{ + mkshort_handle = mkshort_new_handle(); + + HxWFile = xcalloc(GM100_WPO_FILE_SIZE, 1); + + strcpy (fOutname,fname); +} + + + + + +static void wr_deinit(void) +{ + mkshort_del_handle(mkshort_handle); + +} + + + +static void data_read(void) +{ + char name[9], desc[90]; + double lat,lon; + unsigned char *HxWpt; + waypoint *wpt_tmp; + int iCount; + int iDataRead; + int iWptNum; + int iWptIndex; + WPT *pWptHxTmp; + struct tm tm; + struct tm *ptm; + + + HxWpt = xcalloc(GM100_WPO_FILE_SIZE, 1); + + /* read the wpo file to the data-array */ + iDataRead = fread( HxWpt, 1, GM100_WPO_FILE_SIZE, file_in ); + + if (iDataRead == 0) + { + fatal("GPSBABEL: Error reading data from .wpo file\n"); + } + + iWptNum = le_read16(&((WPTHDR *)HxWpt)->num); + + /* Get the waypoints */ + for (iCount = 0; iCount < iWptNum ; iCount ++) + { + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + + iWptIndex = le_read16(&((WPTHDR *)HxWpt)->idx[iCount]); + pWptHxTmp = (WPT *)&HxWpt[OFFS_WPT + (sizeof(WPT) * iWptIndex)]; + + wpt_tmp->altitude = 0; + strncpy(name,pWptHxTmp->name,sizeof(pWptHxTmp->name)); + name[sizeof(pWptHxTmp->name)]=0; + + strncpy(desc,pWptHxTmp->comment,sizeof(pWptHxTmp->comment)); + desc[sizeof(pWptHxTmp->comment)]=0; + + wpt_tmp->shortname = xstrdup(name); + wpt_tmp->description = xstrdup(desc); + + wpt_tmp->creation_time = 0; + if (pWptHxTmp->date.year) + { + ptm = gmtime((time_t*)&pWptHxTmp->time); + tm.tm_hour = ptm->tm_hour; + tm.tm_min = ptm->tm_min; + tm.tm_sec = ptm->tm_sec; + + tm.tm_mday = pWptHxTmp->date.day; + tm.tm_mon = pWptHxTmp->date.month - 1; + tm.tm_year = pWptHxTmp->date.year - 1900; + wpt_tmp->creation_time = mktime(&tm); + } + + lon = le_read32(&pWptHxTmp->pt.iLongitude) / 36000.0; + lat = (le_read32(&pWptHxTmp->pt.iLatitude) / 36000.0) * -1.0; + wpt_tmp->longitude = lon; + wpt_tmp->latitude = lat; + waypt_add(wpt_tmp); + } + xfree(HxWpt); +} + + + + +char *mknshort (char *stIn,unsigned int sLen) +{ + #define MAX_STRINGLEN 255 + static char strOut[MAX_STRINGLEN]; + char strTmp[MAX_STRINGLEN]; + char *shortstr = NULL; + + if (sLen > MAX_STRINGLEN) + return (stIn); + + if (stIn == NULL) + return NULL; + + setshort_length(mkshort_handle, sLen); + setshort_mustuniq(mkshort_handle, 0); + + shortstr = mkshort(mkshort_handle, stIn); + strcpy(strTmp,shortstr); + xfree(shortstr); + + memset(strOut,' ', MAX_STRINGLEN); + strncpy (strOut,strTmp,strlen(strTmp)); + return (strOut); +} + + + + +static void holux_disp(const waypoint *wpt) +{ + double lon,lat; + struct tm *tm; + short sIndex; + WPT *pWptHxTmp; + + lon =(double)wpt->longitude * 36000; + lat =(double)wpt->latitude * -36000; + + + /* round it to increase the accuracy */ + lon += (double)((int)lon/abs((int)lon)) * .5; + lat += (double)((int)lat/abs((int)lat)) * .5; + + + sIndex = le_read16(&((WPTHDR *)HxWFile)->num); + ((WPTHDR *)HxWFile)->idx[sIndex] = sIndex; /* set the waypoint index */ + le_write16(&((WPTHDR *)HxWFile)->idx[sIndex], sIndex); /* set the waypoint index */ + ((WPTHDR *)HxWFile)->used[sIndex] = 0xff; /* Waypoint used */ + + + /* set Waypoint */ + pWptHxTmp = (WPT *)&HxWFile[OFFS_WPT + (sizeof(WPT) * sIndex)]; + + memset (pWptHxTmp->name,0x20,sizeof(pWptHxTmp->name)); + if (wpt->shortname != NULL) + strncpy(pWptHxTmp->name, mknshort(wpt->shortname,sizeof(pWptHxTmp->name)),sizeof(pWptHxTmp->name)); + else + sprintf(pWptHxTmp->name,"W%d",sIndex); + + memset (pWptHxTmp->comment,0x20,sizeof(pWptHxTmp->comment)); + if (wpt->description != NULL) + strncpy(pWptHxTmp->comment, mknshort(wpt->description,sizeof(pWptHxTmp->comment)),sizeof(pWptHxTmp->comment)); + + /*set the time */ + if (wpt->creation_time) + { + /* tm = gmtime(&wpt->creation_time);*/ /* I get the wrong result with gmtime ??? */ + tm = localtime(&wpt->creation_time); + pWptHxTmp->time = (tm->tm_hour * 3600) + (tm->tm_min * 60) +tm->tm_sec; + pWptHxTmp->date.day = tm->tm_mday; + pWptHxTmp->date.month = tm->tm_mon + 1; + pWptHxTmp->date.year = tm->tm_year + 1900; + } + else + { + pWptHxTmp->time = 0; + pWptHxTmp->date.day = 0; + pWptHxTmp->date.month = 0; + pWptHxTmp->date.year = 0; + } + + + le_write32(&pWptHxTmp->pt.iLatitude,(unsigned int) lat); + le_write32(&pWptHxTmp->pt.iLongitude,(unsigned int) lon); + pWptHxTmp->checked = 01; + pWptHxTmp->vocidx = (short)0xffff; + le_write16(&((WPTHDR *)HxWFile)->num, ++sIndex); + le_write16(&((WPTHDR *)HxWFile)->next, ++sIndex); +} + + + + + + +static void data_write(void) +{ + int iWritten; + FILE *file_out; + short sCount; + + /* init the waypoint area*/ + le_write32(&((WPTHDR *)HxWFile)->id, WPT_HDR_ID); + ((WPTHDR *)HxWFile)->num = 0; + ((WPTHDR *)HxWFile)->next = 0; + + /* clear index list */ + for (sCount = 0; sCount < MAXWPT; sCount++) + ((WPTHDR *)HxWFile)->idx[sCount] = (signed short)-1; + for (sCount = 0; sCount < MAXWPT; sCount++) + ((WPTHDR *)HxWFile)->used[sCount] = 0; + + /* init the route area */ + le_write32(&((RTEHDR *)&HxWFile[ROUTESTART])->id, RTE_HDR_ID); + ((RTEHDR *)&HxWFile[ROUTESTART])->num = 0; + le_write16(&((RTEHDR *)&HxWFile[ROUTESTART])->next, 1); + ((RTEHDR *)&HxWFile[ROUTESTART])->rteno = (signed short)-1; + + /* clear index list */ + for (sCount = 0; sCount < MAXRTE; sCount++) + ((RTEHDR *)&HxWFile[ROUTESTART])->idx[sCount] = (signed short)-1; + for (sCount = 0; sCount < MAXRTE; sCount++) + ((RTEHDR *)&HxWFile[ROUTESTART])->used[sCount] = 0; + + waypt_disp_all(holux_disp); + + + file_out = xfopen(fOutname, "wb", MYNAME); + + iWritten = fwrite (HxWFile, 1, GM100_WPO_FILE_SIZE,file_out); + if (iWritten == 0) + { + fatal("GPSBABEL: Error writing .%s\n", fOutname); + } + + fclose(file_out); + xfree(HxWFile); +} + + + + +ff_vecs_t holux_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL +}; diff --git a/holux.h b/holux.h new file mode 100644 index 000000000..cab9e077c --- /dev/null +++ b/holux.h @@ -0,0 +1,117 @@ +/* + holux.h + Copyright (C) 2002 Jochen Becker, jb@bepo.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + + /* header file for the holux gm-100 wpo format */ + +#ifndef BYTE +#define BYTE unsigned char +#endif + +#ifndef WORD +#define WORD unsigned short +#endif + +#ifndef DWORD +#define DWORD unsigned int +#endif + + +/* #define GM100_WPO_FILE_SIZE 25512 */ /* size of a holux gm-100 wpo file used by mapShow 1.4*/ +#define GM100_WPO_FILE_SIZE 25600 /* size of a holux gm-100 wpo file used by the GM-100*/ + +#define ROUTESTART 23600 /* Offset for start of route */ +#define MAXWPT 500 /* max number of waypoint */ +#define MAXRTE 20 /* max number of routes */ +#define MAXWPTINRTE 30 + +#define WPT_HDR_ID 0x5C38A631 /* waypoint header */ +#define RTE_HDR_ID 0xD87F59F0 /* route header */ + + + /* Offsets */ +#define OFFS_WPT 0x05E4 /* offet for waypoint table */ + + +typedef struct tagWPTHDR +{ + DWORD id; /* WPT_HDR_ID */ + short num; /* Current wpt number */ + short next; /* next wpt number */ + short idx[MAXWPT]; /* saving wpt index here for each wpt, default was -1*/ + BYTE used[MAXWPT]; /* Have the match wpt been used (0xFF), Default was 0 */ +}WPTHDR; + + + + +typedef struct tagPOINT +{ + signed int iLongitude; + signed int iLatitude; +}POINT; + + + + +typedef struct tagDATE +{ + BYTE day; + BYTE month; + short year; +}HX_DATE; + + +typedef struct tagWPT +{ + char name[8]; /* wpt name */ + char comment[12]; /* comment string */ + POINT pt; /* waypoint location */ + short vocidx; /* voice index, not used */ + short usecount; /* counter: times used by routes */ + HX_DATE date; /* date */ + unsigned time; /* time */ + char checked; /* Active or not */ + BYTE dummy[3]; /* fill bytes */ +}WPT; + + + +typedef struct tagRTEHDR +{ + DWORD id; /* RTE_HDR_ID */ + short num; /* Current route number */ + short next; /* next route number */ + signed short idx[MAXRTE]; /* saving route index here for each route, default was -1 */ + BYTE used[MAXRTE]; /* Have the wpt been used (0xFF), Default was 0 */ + signed short rteno; /* Saving navigationroute number here */ +}RTEHDR; + + +typedef struct tagRTE +{ + char name[8]; /* route name */ + char comment[12]; /* comment string */ + short wptnum; /* the total waypoint number */ + short wptidx[MAXWPTINRTE]; /* the waypoint index in this route */ + short reserved; + int date; /* date */ + int time; /* time */ +}RTE; + diff --git a/hsa_ndv.c b/hsa_ndv.c new file mode 100644 index 000000000..7cfa2c66d --- /dev/null +++ b/hsa_ndv.c @@ -0,0 +1,553 @@ +/* + Copyright (C) 2004 HSA Systems, Sven Dowideit + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include "defs.h" +#if !NO_EXPAT +#include +static XML_Parser psr; +#endif + +static char *cdatastr; +static int in_Route = 0; +static int in_ChartWork = 0; +static int in_Object = 0; + +static waypoint *wpt_tmp; +char *routeName = "ROUTENAME"; + +#define REPLACEMENT_SIRIUS_ATTR_SEPARATOR ';' +#define ATTR_USRMRK "usrmrk" +#define ATTR_OBJECTNAME "OBJNAM" +#define ATTR_SHIPNAME "shpnam" + +void readVersion4( FILE* pFile); + +FILE *fd; +FILE *ofd; + +static +arglist_t hsa_ndv_args[] = { + {0, 0, 0, 0, 0} +}; + +#define MYNAME "HsaNdv" +#define MY_CBUF 4096 + +#define TRUE 1 +#define FALSE 0 + + +#if NO_EXPAT +void +hsa_ndv_rd_init(const char *fname) +{ + fatal(MYNAME ": This build excluded HSA Endeavour support because expat was not installed.\n"); +} + +void +hsa_ndv_read(void) +{ +} +#else + +static void +hsa_ndv_start(void *data, const char *el, const char **attr) +{ +// printf("<%s>\n", el); + if (strcmp(el, "Export") == 0) + {//should only be one + } + else if (strcmp(el, "Route") == 0) + { + in_Route++; + } + else if (strcmp(el, "Chartwork") == 0) + { + in_ChartWork++; + } + else if (strcmp(el, "Object") == 0) + { + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + wpt_tmp->altitude = unknown_alt; + in_Object++; + } + //reset data :) + memset(cdatastr,0, MY_CBUF); +} + +static void getAttr(const char *data, const char *attr, char **val, char seperator) +{ + char *start; + if ((start = strstr(data, attr)) != NULL) + { + char *end; + int len; + + end = strchr(start, seperator); + if (end == NULL) + { + end = start + strlen(start);//assume we are teh last attr + } + + len = end-start - strlen(attr); + + *val = xcalloc(len+1, 1); + memcpy(*val, start+strlen(attr), len); + (*val)[len] = '\0'; + } + else + { + *val = xcalloc(1, 1); + (*val)[0] = '\0'; + } +} + +static void +hsa_ndv_end(void *data, const char *el) +{ + if (in_Route) + { + if (strcmp(el, "Version") == 0) + {//don't really care + } + else if (strcmp(el, "Name") == 0) + { + routeName = xstrdup(cdatastr); + } + else if (strcmp(el, "LastModified") == 0) + {//don't really care + } + if (in_Object) + { + if (strcmp(el, "ClassName") == 0) + { + } + else if (strcmp(el, "Attr") == 0) + { + getAttr(cdatastr, ATTR_OBJECTNAME, &wpt_tmp->shortname, REPLACEMENT_SIRIUS_ATTR_SEPARATOR); + getAttr(cdatastr, ATTR_USRMRK, &wpt_tmp->description, REPLACEMENT_SIRIUS_ATTR_SEPARATOR); + } + else if (strcmp(el, "LegAttr") == 0) + { + } + else if (strcmp(el, "NumberOfVertexs") == 0) + { + } + else if (strcmp(el, "Latitude") == 0) + { + wpt_tmp->latitude = atof(cdatastr); + } + else if (strcmp(el, "Longitude") == 0) + { + wpt_tmp->longitude = atof(cdatastr); + } + } + } + + if (in_ChartWork) + { + if (strcmp(el, "Version") == 0) + {//don't really care + } + if (in_Object) + { + if (strcmp(el, "ClassName") == 0) + { +// className = xstrdup(cdatastr); + } + else if (strcmp(el, "Attr") == 0) + { + //getAttr(cdatastr, ATTR_OBJECTNAME, &wpt_tmp->shortname, REPLACEMENT_SIRIUS_ATTR_SEPARATOR); + //getAttr(cdatastr, ATTR_SHIPNAME, &wpt_tmp->description, REPLACEMENT_SIRIUS_ATTR_SEPARATOR); + } + else if (strcmp(el, "NumberOfVertexs") == 0) + { + } + else if (strcmp(el, "Latitude") == 0) + { + wpt_tmp->latitude = atof(cdatastr); + } + else if (strcmp(el, "Longitude") == 0) + { + wpt_tmp->longitude = atof(cdatastr); + } + else if (strcmp(el, "Time") == 0) + { + wpt_tmp->creation_time = atoi(cdatastr); + } + } + } + + //ignore everything else for now.. + memset(cdatastr,0, MY_CBUF); + + if (strcmp(el, "Object") == 0) + { + if (in_Route) + { + waypt_add(wpt_tmp); + } + else if (in_ChartWork) + { + //TODO: not sure how i want to handle this.. + } + in_Object--; + } + else if (strcmp(el, "Route") == 0) + { + in_Route--; + } + else if (strcmp(el, "Chartwork") == 0) + { + in_ChartWork--; + } +} + +static void +hsa_ndv_cdata(void *dta, const XML_Char *s, int len) +{ + char *estr; + estr = cdatastr + strlen(cdatastr); + memcpy(estr, s, len); +} + +void +hsa_ndv_rd_init(const char *fname) +{ + fd = xfopen(fname, "r", MYNAME); + + psr = XML_ParserCreate(NULL); + if (!psr) { + fatal(MYNAME ":Cannot create XML parser\n"); + } + + XML_SetElementHandler(psr, hsa_ndv_start, hsa_ndv_end); + cdatastr = xcalloc(MY_CBUF,1); + XML_SetCharacterDataHandler(psr, hsa_ndv_cdata); +} + +void +hsa_ndv_read(void) +{ + int len; + char buf[MY_CBUF]; + memset(buf, 0, MY_CBUF); + + while ((len = fread(buf, 1, sizeof(buf), fd))) + { + char *bad; + + if (NULL != strstr(buf, "nver=1")) + {//its the older format, not xml + fseek(fd, 0, SEEK_SET); + readVersion4(fd); + break; + } + //grumble - have to remove \x1f's from sirius attributes + while (NULL != (bad = strchr(buf, '\x1f'))) + { + *bad = REPLACEMENT_SIRIUS_ATTR_SEPARATOR; + } + if (!XML_Parse(psr, buf, len, feof(fd))) { + fatal(MYNAME ":Parse error at %d: %s\n", + XML_GetCurrentLineNumber(psr), + XML_ErrorString(XML_GetErrorCode(psr))); + } + } + + XML_ParserFree(psr); +} + +#endif + +void +hsa_ndv_rd_deinit(void) +{ + if ( cdatastr ) { + xfree(cdatastr); + } + fclose(fd); +} + +void +hsa_ndv_wr_init(const char *fname) +{ + ofd = xfopen(fname, "w", MYNAME); +} + +void +hsa_ndv_wr_deinit(void) +{ + fclose(ofd); +} + +static int legNum = 0; + +static void +hsa_ndv_waypt_pr(const waypoint *waypointp) +{ + + fprintf(ofd, "\t\t\n"); + + fprintf(ofd, "\t\t\twaypnt\n"); +//ignore these for now, they are s57 specific +// fprintf(ofd, "\t\t\t0\n"); +// fprintf(ofd, "\t\t\t1\n"); +// fprintf(ofd, "\t\t\t1089009023\n"); + fprintf(ofd, "\t\t\tattr=grpnam%s\x1ftrnrad50\x1fOBJNAM%s\x1flegnum%i\x1fusrmrk%s\x1fselect2\n", + routeName, waypointp->shortname, legNum, waypointp->description); + fprintf(ofd, "\t\t\tattr=grpnam%s\x1f\n", routeName); + fprintf(ofd, "\t\t\t1\n"); + fprintf(ofd, "\t\t\t%lf\n", waypointp->latitude); + fprintf(ofd, "\t\t\t%lf\n", waypointp->longitude); + + fprintf(ofd, "\t\t\n"); + + legNum++; +} + +void +hsa_ndv_write(void) +{ + fprintf(ofd, "\n"); + fprintf(ofd, "\n"); + fprintf(ofd, "\t\n"); + fprintf(ofd, "\t\t1.0000000\n"); + fprintf(ofd, "\t\tROUTENAME\n"); /*TODO: used filename? */ + fprintf(ofd, "\t\t0\n"); + waypt_disp_all(hsa_ndv_waypt_pr); + fprintf(ofd, "\t\n"); + +//later we'll import past tracks and chart objects? +// fprintf(ofd, "\t\n"); +// fprintf(ofd, "\t\t1.0000000\n"); +// track_disp_all(hsa_ndv_track_pr); +// fprintf(ofd, "\t\n"); + + + fprintf(ofd, "\n"); +} + +ff_vecs_t HsaEndeavourNavigator_vecs = { + ff_type_file, + hsa_ndv_rd_init, + hsa_ndv_wr_init, + hsa_ndv_rd_deinit, + hsa_ndv_wr_deinit, + hsa_ndv_read, + hsa_ndv_write, + NULL, + hsa_ndv_args +}; + +////////////////////////////////////////////////////////////////////////// +// older style Endeavour route export file +//read DEC2000 NDV export files + +#define EF_RECORD_DELIMTER 0 +#define ED_REC_NAME_SIZE 5 +#define EF_NVER_REC "nver=" +#define EF_LAT_REC "lati=" +#define EF_LONG_REC "long=" +#define EF_TIME_REC "time=" +#define EF_ATTR_REC "attr=" +#define EF_CLNM_REC "clnm=" +#define INVALID_TIME -1L +#define SOUNDARRAY_CHAR 'S' + +int readRecord( FILE* pFile, const char* pRecName, char *recData); +int readPositionRecord( FILE* pFile, double* lat, double* lng, long* timeStamp); + +void readVersion4( FILE* pFile) +{ + while( TRUE ) + { + char recData[256]; + // get the position + double lat2, lng2; + + // set the pointer to the time stamp depending + // on whether we have a sounding array or not + long ts1, ts2; + long* pts1 = 0; + long* pts2 = 0; + + int soundArray = FALSE; + int numberOfVerticies; + char className[256]; + char attr[1024]; + int Vertex; + + memset(attr, 0, 1024); + + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + wpt_tmp->altitude = unknown_alt; + + // read the first record + if( !readRecord( pFile, EF_NVER_REC, recData) ) + // no first record then finished + break; + + // get the type + sscanf( (const char*)recData, "%d", &numberOfVerticies); + + // do we have a sounding array + if( *((const char *)recData + strlen(recData) - 1) == SOUNDARRAY_CHAR ) + { + soundArray = TRUE; + } + + if( soundArray ) + { + pts1 = &ts1; + pts2 = &ts2; + } + + // go through the vertices + for( Vertex = 0; Vertex < numberOfVerticies; Vertex++) + { + // read vertex position + if( !readPositionRecord( pFile, &lat2, &lng2, pts2) ) { + xfree(wpt_tmp); + return; + } + + wpt_tmp->longitude = lng2; + wpt_tmp->latitude = lat2; + break;//TODO: ignore more points for now + } + + + // read the class name + if( !readRecord( pFile, EF_CLNM_REC, className) ) { + xfree( wpt_tmp ); + return; + } + + // read the attributes name + if( !readRecord( pFile, EF_ATTR_REC, attr) ) { + xfree( wpt_tmp ); + return; + } + getAttr(attr, ATTR_OBJECTNAME, &wpt_tmp->shortname, '\x1f'); + getAttr(attr, ATTR_USRMRK, &wpt_tmp->description, '\x1f'); + + { + char *bad; + //remove \n and \x1f from description data + while (NULL != (bad = strchr(wpt_tmp->description, '\x1f'))) + { + *bad = REPLACEMENT_SIRIUS_ATTR_SEPARATOR; + } + while (NULL != (bad = strchr(wpt_tmp->description, '\n'))) + { + *bad = ' '; + } + while (NULL != (bad = strchr(wpt_tmp->description, '\r'))) + { + *bad = ' '; + } + } + + waypt_add(wpt_tmp); + } + + fclose(pFile); + return; +} + +// read a record to a file +int readRecord( FILE* pFile, const char* pRecName, char *recData) +{ + // get the rec name + int len; + char recName[ED_REC_NAME_SIZE+1]; + char arrRecData[256]; + + for( len = 0; len < ED_REC_NAME_SIZE; len++) + { + int c = fgetc( pFile); + + // if we hit EOF failed + if( c == EOF ) + return FALSE; + + recName[len] = c; + } + + // if the record name is not the reqiured type then error + if( strncmp( recName, pRecName, ED_REC_NAME_SIZE) != 0 ) + return FALSE; + + // get the rec data + for( len = 0; TRUE; len++) + { + int c = fgetc( pFile); + + // if we hit EOF failed + if( c == EOF ) + return FALSE; + + // hit end of line + if( c == EF_RECORD_DELIMTER ) + break; + + arrRecData[len] = c; + } + + // get the rec data to a string + strncpy(recData, arrRecData, len); + + return TRUE; +} + +// read position +int readPositionRecord( FILE* pFile, double* lat, double* lng, + long* timeStamp) +{ + // read the lat record + char recData[256]; + if( !readRecord( pFile, EF_LAT_REC, recData) ) + // no lat record then finished + return FALSE; + + // read the latitude + sscanf( (const char*)recData, "%lf", lat); + + // read the lng record + if( !readRecord( pFile, EF_LONG_REC, recData) ) + // no first record then finished + return FALSE; + + // read the latitude + sscanf( (const char*)recData, "%lf", lng); + + // if we are to read a time record + if( timeStamp ) + { + // read the lng record + if( !readRecord( pFile, EF_TIME_REC, recData) ) + // no first record then finished + return FALSE; + + // read the latitude + sscanf( (const char*)recData, "%ld", timeStamp); + } + + return TRUE; +} diff --git a/html.c b/html.c new file mode 100644 index 000000000..bc00b547e --- /dev/null +++ b/html.c @@ -0,0 +1,265 @@ +/* + Output only format for Human Readable formats. + + Copyright (C) 2004 Scott Brynen, scott (at) brynen.com + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA +*/ + + +#include "defs.h" +#include "jeeps/gpsmath.h" +#include + +static FILE *file_out; +static void *mkshort_handle; + +static char *stylesheet = NULL; +static char *encrypt = NULL; +static char *includelogs = NULL; + +#define MYNAME "HTML" + +static +arglist_t html_args[] = { + { "stylesheet", &stylesheet, + "Path to HTML style sheet", NULL, ARGTYPE_STRING }, + { "encrypt", &encrypt, + "Encrypt hints using ROT13", NULL, ARGTYPE_BOOL }, + { "logs", &includelogs, + "Include groundspeak logs if present", NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + + + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "w", MYNAME); + mkshort_handle = mkshort_new_handle(); +} + +static void +wr_deinit(void) +{ + fclose(file_out); + mkshort_del_handle(mkshort_handle); +} + +static void +html_disp(const waypoint *wpt) +{ + int latint, lonint; + char tbuf[1024]; + time_t tm = wpt->creation_time; + long utmz; + double utme, utmn; + char utmzc; + + lonint = abs(wpt->longitude); + latint = abs(wpt->latitude); + GPS_Math_WGS84_To_UTM_EN(wpt->latitude, wpt->longitude, + &utme, &utmn, &utmz, &utmzc); + + if (tm == 0) + tm = time(NULL); + strftime(tbuf, sizeof(tbuf), "%d-%b-%Y", localtime(&tm)); + + + fprintf(file_out, "
\n"); + fprintf(file_out, "
\n", wpt->shortname); + fprintf(file_out, "

%s - %c%d°%06.3f %c%d°%06.3f (%ld%c %6.0f %7.0f)", + (global_opts.synthesize_shortnames) ? mkshort(mkshort_handle, wpt->description) : wpt->shortname, + wpt->latitude < 0 ? 'S' : 'N', latint, 60.0 * (fabs(wpt->latitude) - latint), + wpt->longitude < 0 ? 'W' : 'E', lonint, 60.0 * (fabs(wpt->longitude) - lonint), + utmz, utmzc, utme, utmn); + if (wpt->altitude != unknown_alt) + fprintf (file_out, " alt: %1.1f", wpt->altitude); + fprintf (file_out, "
\n"); + + if (strcmp(wpt->description, wpt->shortname)) { + if (wpt->url) { + char *d = html_entitize(wpt->description); + fprintf(file_out, "%s

\n", wpt->url, d); + xfree(d); + } + else { + fprintf(file_out, "%s\n", wpt->description); + } + + } + if (wpt->gc_data.terr) { + if (wpt->gc_data.desc_short.utfstring) { + fprintf (file_out, "

%s

\n", strip_nastyhtml(wpt->gc_data.desc_short.utfstring)); + } + if (wpt->gc_data.desc_long.utfstring) { + fprintf (file_out, "

%s

\n", strip_nastyhtml(wpt->gc_data.desc_long.utfstring)); + } + if (wpt->gc_data.hint) { + char *hint = NULL; + if ( encrypt ) + hint = rot13( wpt->gc_data.hint ); + else + hint = xstrdup( wpt->gc_data.hint ); + fprintf (file_out, "

Hint: %s

\n", hint); + xfree( hint ); + } + } + else if (wpt->notes && (!wpt->description || strcmp(wpt->notes,wpt->description))) { + fprintf (file_out, "

%s

\n", wpt->notes); + } + if ( includelogs && wpt->gpx_extras ) { + xml_tag *root = wpt->gpx_extras; + xml_tag *curlog = NULL; + xml_tag *logpart = NULL; + curlog = xml_findfirst( root, "groundspeak:log" ); + while ( curlog ) { + time_t logtime = 0; + struct tm *logtm = NULL; + fprintf( file_out, "

\n" ); + + logpart = xml_findfirst( curlog, "groundspeak:type" ); + if ( logpart ) { + fprintf( file_out, "%s by ", logpart->cdata ); + } + + logpart = xml_findfirst( curlog, "groundspeak:finder" ); + if ( logpart ) { + char *f = html_entitize( logpart->cdata ); + fprintf( file_out, "%s on ", f ); + xfree( f ); + } + + logpart = xml_findfirst( curlog, "groundspeak:date" ); + if ( logpart ) { + logtime = xml_parse_time( logpart->cdata ); + logtm = localtime( &logtime ); + if ( logtm ) { + fprintf( file_out, + "%2.2d/%2.2d/%4.4d
\n", + logtm->tm_mon+1, + logtm->tm_mday, + logtm->tm_year+1900 + ); + } + } + + logpart = xml_findfirst( curlog, "groundspeak:log_wpt" ); + if ( logpart ) { + char *coordstr = NULL; + float lat = 0; + int latdeg = 0; + float lon = 0; + int londeg = 0; + coordstr = xml_attribute( logpart, "lat" ); + if ( coordstr ) { + lat = atof( coordstr ); + } + coordstr = xml_attribute( logpart, "lon" ); + if ( coordstr ) { + lon = atof( coordstr ); + } + latdeg = abs(lat); + londeg = abs(lon); + + fprintf( file_out, + "%c %d° %.3f' %c %d° %.3f'
\n", + + lat < 0 ? 'S' : 'N', latdeg, 60.0 * (fabs(lat) - latdeg), + lon < 0 ? 'W' : 'E', londeg, 60.0 * (fabs(lon) - londeg) + ); + } + + logpart = xml_findfirst( curlog, "groundspeak:text" ); + if ( logpart ) { + char *encstr = NULL; + char *s = NULL; + char *t = NULL; + int encoded = 0; + encstr = xml_attribute( logpart, "encoded" ); + encoded = (encstr[0] != 'F'); + + if ( encrypt && encoded ) { + s = rot13( logpart->cdata ); + } + else { + s = xstrdup( logpart->cdata ); + } + + t = html_entitize( s ); + fprintf( file_out, "%s", t ); + xfree( t ); + xfree( s ); + } + + fprintf( file_out, "

\n" ); + curlog = xml_findnext( root, curlog, "groundspeak:log" ); + } + } + fprintf(file_out, "
\n"); +} + +static void +html_index(const waypoint *wpt) +{ + char *sn = html_entitize(wpt->shortname); + char *d = html_entitize(wpt->description); + + fprintf(file_out, "%s - %s
\n", sn, sn, d); + + xfree(sn); + xfree(d); +} + +static void +data_write(void) +{ + setshort_length(mkshort_handle, 6); + + fprintf(file_out, "\n"); + fprintf(file_out, "\n"); + fprintf(file_out, "\n"); + fprintf(file_out, " GPSBabel HTML Output\n"); + fprintf(file_out, " \n"); + if (stylesheet) + fprintf(file_out, " \n", stylesheet); + fprintf(file_out, "\n"); + fprintf(file_out, "\n"); + + fprintf(file_out, "

\n"); + waypt_disp_all(html_index); + fprintf(file_out, "

\n"); + + waypt_disp_all(html_disp); + + fprintf(file_out, ""); + fprintf(file_out, ""); + +} + + +ff_vecs_t html_vecs = { + ff_type_file, + NULL, + wr_init, + NULL, + wr_deinit, + NULL, + data_write, + NULL, + html_args +}; diff --git a/igc.c b/igc.c new file mode 100644 index 000000000..5ccbfb0c6 --- /dev/null +++ b/igc.c @@ -0,0 +1,905 @@ +/* + * FAI/IGC data format translation. + * + * Refer to Appendix 1 of + * http://www.fai.org:81/gliding/gnss/tech_spec_gnss.asp for the + * specification of the IGC data format. This translation code was + * written when the latest ammendment list for the specification was AL6. + * + * Copyright (C) 2004 Chris Jones + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111 USA + */ + +#include "defs.h" +#include + +static FILE *file_in; +static FILE *file_out; +static char manufacturer[4]; +static const route_head *head; +static char *timeadj = NULL; + +#define MYNAME "IGC" +#define MAXRECLEN 79 // Includes null terminator and CR/LF +#define MAXDESCLEN 1024 +#define PRESTRKNAME "PRESALTTRK" +#define GNSSTRKNAME "GNSSALTTRK" +#define HDRMAGIC "IGCHDRS" +#define HDRDELIM "~" +#define DATEMAGIC "IGCDATE" + +/* + * IGC record types. + * These appear as the first char in each record. + */ +typedef enum { + rec_manuf_id = 'A', // FR manufacturer and identification + rec_fix = 'B', // Fix + rec_task = 'C', // Task/declaration + rec_diff_gps = 'D', // Differential GPS + rec_event = 'E', // Event + rec_constel = 'F', // Constellation + rec_security = 'G', // Security + rec_header = 'H', // File header + rec_fix_defn = 'I', // List of extension data included at end of each fix (B) record + rec_extn_defn = 'J', // List of data included in each extension (K) record + rec_extn_data = 'K', // Extension data + rec_log_book = 'L', // Logbook/comments + + // M..Z are spare + + rec_none = 0, // No record + rec_bad = 1, // Bad record +} igc_rec_type_t; + +/* + * See if two lat/lon pairs are approximately equal. + * @param lat1 The latitude of coordinate pair 1 + * @param lon1 The longitude of coordinate pair 1 + * @param lat2 The latitude of coordinate pair 2 + * @param lon2 The longitude of coordinate pair 2 + * @retval 1 The coordinates are approximately equal + * @retval 0 The coordinates are significantly different + */ +static unsigned char coords_match(double lat1, double lon1, double lat2, double lon2) +{ + return (fabs(lat1 - lat2) < 0.0001 && fabs(lon1 - lon2) < 0.0001) ? 1 : 0; +} + +/************************************************************************************************* + * Input file processing + */ + +/* + * Get an IGC record from the input file + * @param rec Caller allocated storage for the record. At least MAXRECLEN chars must be allocated. + * @return the record type. rec_none on EOF, rec_bad on fgets() or parse error. + */ +static igc_rec_type_t get_record(char *rec) +{ + size_t len; + + if (fgets(rec, MAXRECLEN, file_in) == NULL) { + if (feof(file_in)) { + return rec_none; + } else { + warning(MYNAME " fgets(): %s\n", strerror(errno)); + return rec_bad; + } + } + len = strlen(rec); + if (len < 3 || rec[len - 2] != '\r' || rec[len - 1] != '\n' || rec[0] < 'A' || rec[0] > 'Z') { + warning(MYNAME " bad input record: '%s'\n", rec); + return rec_bad; + } + rec[len - 2] = '\0'; + return (igc_rec_type_t) rec[0]; +} + +static void rd_init(const char *fname) +{ + char ibuf[MAXRECLEN]; + + file_in = xfopen(fname, "rb", MYNAME); + + // File must begin with a manufacturer/ID record + if (get_record(ibuf) != rec_manuf_id || sscanf(ibuf, "A%3[A-Z]", manufacturer) != 1) { + fatal(MYNAME ": %s is not an IGC file\n", fname); + } +} + +static void rd_deinit(void) +{ + fclose(file_in); +} + +/** + * Handle pre- or post-flight task declarations. + * A route is created for each set of waypoints in a task declaration. + * @param rec A single task record + */ +static void igc_task_rec(const char *rec) +{ + static char flight_date[7]; + static unsigned int num_tp, tp_ct; + static route_head *rte_head; + static time_t creation; + + char task_num[5]; + char task_desc[MAXRECLEN]; + waypoint *wpt; + unsigned int lat_deg, lat_min, lat_frac; + unsigned int lon_deg, lon_min, lon_frac; + char lat_hemi[2], lon_hemi[2]; + char short_name[8]; + char tmp_str[MAXRECLEN]; + struct tm tm; + + static enum { id, takeoff, start, turnpoint, finish, landing } state = id; + + // First task record identifies the task to follow + if (id == state) { + task_desc[0] = '\0'; + if (sscanf(rec, "C%2u%2u%2u%2u%2u%2u%6[0-9]%4c%2u%[^\r]\r\n", + &tm.tm_mday, &tm.tm_mon, &tm.tm_year, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec, + flight_date, task_num, &num_tp, task_desc) < 9) { + fatal(MYNAME ": task id (C) record parse error\n'%s'", rec); + } + task_num[4] = '\0'; + tm.tm_mon -= 1; + if (tm.tm_year < 70) { + tm.tm_year += 100; + } + tm.tm_isdst = 0; + creation = mktime(&tm) + get_tz_offset(); + + // Create a route to store the task data in. + rte_head = route_head_alloc(); + rte_head->rte_name = xstrdup(task_num); + sprintf(tmp_str, DATEMAGIC "%s: %s", flight_date, task_desc); + rte_head->rte_desc = xstrdup(tmp_str); + route_add_head(rte_head); + state++; + return; + } + // Get the waypoint + tmp_str[0] = '\0'; + if (sscanf(rec, "C%2u%2u%3u%1[NS]%3u%2u%3u%1[WE]%[^\r]\r\n", + &lat_deg, &lat_min, &lat_frac, lat_hemi, + &lon_deg, &lon_min, &lon_frac, lon_hemi, tmp_str) < 8) { + fatal(MYNAME ": task waypoint (C) record parse error\n%s", rec); + } + + wpt = waypt_new(); + wpt->latitude = ('N' == lat_hemi[0] ? 1 : -1) * + (lat_deg + (lat_min * 1000 + lat_frac) / 1000.0 / 60); + + wpt->longitude = ('E' == lon_hemi[0] ? 1 : -1) * + (lon_deg + (lon_min * 1000 + lon_frac) / 1000.0 / 60); + + wpt->creation_time = creation; + wpt->description = xstrdup(tmp_str); + + // Name the waypoint according to the order of the task record + switch (state) { + case takeoff: + snprintf(short_name, 8, "TAKEOFF"); + state++; + break; + + case start: + snprintf(short_name, 8, "START"); + tp_ct = 0; + state++; + break; + + case turnpoint: + if (++tp_ct == num_tp) { + state++; + } + snprintf(short_name, 8, "TURN%02u", tp_ct); + break; + + case finish: + snprintf(short_name, 8, "FINISH"); + state++; + break; + + case landing: + snprintf(short_name, 8, "LANDING"); + state = id; + break; + + default: + fatal(MYNAME ": task id (C) record internal error\n%s", rec); + break; + } + + // Zero lat and lon indicates an unknown waypoint + if (coords_match(wpt->latitude, wpt->longitude, 0.0, 0.0)) { + waypt_free(wpt); + return; + } + wpt->shortname = xstrdup(short_name); + route_add_wpt(rte_head, wpt); +} + +static void data_read(void) +{ + char ibuf[MAXRECLEN]; + igc_rec_type_t rec_type; + unsigned int hours, mins, secs; + unsigned int lat_deg, lat_min, lat_frac; + unsigned int lon_deg, lon_min, lon_frac; + char lat_hemi[2], lon_hemi[2]; + char validity; + route_head *pres_head = NULL; + route_head *gnss_head = NULL; + int pres_alt, gnss_alt; + char pres_valid = 0; + char gnss_valid = 0; + waypoint *pres_wpt = NULL; + waypoint *gnss_wpt = NULL; + time_t date = 0; + time_t prev_tod = 0; + time_t tod; + struct tm tm; + char tmp_str[20]; + char *hdr_data; + size_t remain; + char trk_desc[MAXDESCLEN + 1]; + + strcpy(trk_desc, HDRMAGIC HDRDELIM); + + while (1) { + rec_type = get_record(ibuf); + switch (rec_type) { + case rec_manuf_id: + // Manufacturer/ID record already found in rd_init(). + warning(MYNAME ": duplicate manufacturer/ID record\n"); + break; + + case rec_header: + // Get the header sub type + if (sscanf(ibuf, "H%*1[FOP]%3s", tmp_str) != 1) { + fatal(MYNAME ": header (H) record parse error\n%s\n%s\n", ibuf, tmp_str); + } + // Optional long name of record sub type is followed by a + // colon. Actual header data follows that. + if (NULL == (hdr_data = strchr(ibuf, ':'))) { + hdr_data = ibuf + 5; + } else { + hdr_data++; + } + + // Date sub type + if (strcmp(tmp_str, "DTE") == 0) { + if (sscanf(hdr_data, "%2u%2u%2u", &tm.tm_mday, &tm.tm_mon, &tm.tm_year) != 3) { + fatal(MYNAME ": date (H) record parse error\n'%s'\n", ibuf); + } + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + tm.tm_mon -= 1; + if (tm.tm_year < 70) { + tm.tm_year += 100; + } + tm.tm_isdst = 0; + date = mktime(&tm) + get_tz_offset(); + } else { + // Store other header data in the track descriptions + if (strlen(trk_desc) < MAXDESCLEN) { + strcat(ibuf, HDRDELIM); + remain = MAXDESCLEN - strlen(trk_desc); + strncat(trk_desc, ibuf, remain); + } + } + break; + + case rec_fix: + // Date must appear in file before the first fix record + if (date < 1000000L) { + fatal(MYNAME ": bad date %ld\n", date); + } + // Create a track for pressure altitude waypoints + if (!pres_head) { + pres_head = route_head_alloc(); + pres_head->rte_name = xstrdup(PRESTRKNAME); + pres_head->rte_desc = xstrdup(trk_desc); + track_add_head(pres_head); + } + // Create a second track for GNSS altitude waypoints + if (!gnss_head) { + gnss_head = route_head_alloc(); + gnss_head->rte_name = xstrdup(GNSSTRKNAME); + gnss_head->rte_desc = xstrdup(trk_desc); + track_add_head(gnss_head); + } + // Create a waypoint from the fix record data + if (sscanf(ibuf, + "B%2u%2u%2u%2u%2u%3u%1[NS]%3u%2u%3u%1[WE]%c%5d%5d", + &hours, &mins, &secs, &lat_deg, &lat_min, &lat_frac, + lat_hemi, &lon_deg, &lon_min, &lon_frac, lon_hemi, + &validity, &pres_alt, &gnss_alt) != 14) { + fatal(MYNAME ": fix (B) record parse error\n%s\n", ibuf); + } + pres_wpt = waypt_new(); + + pres_wpt->latitude = ('N' == lat_hemi[0] ? 1 : -1) * + (lat_deg + (lat_min * 1000 + lat_frac) / 1000.0 / 60); + + pres_wpt->longitude = ('E' == lon_hemi[0] ? 1 : -1) * + (lon_deg + (lon_min * 1000 + lon_frac) / 1000.0 / 60); + + // Increment date if we pass midnight UTC + tod = (hours * 60 + mins) * 60 + secs; + if (tod < prev_tod) { + date += 24 * 60 * 60; + } + prev_tod = tod; + pres_wpt->creation_time = date + tod; + + // Add the waypoint to the pressure altitude track + if (pres_alt) { + pres_valid = 1; + pres_wpt->altitude = pres_alt; + } else { + pres_wpt->altitude = unknown_alt; + } + route_add_wpt(pres_head, pres_wpt); + + // Add the same waypoint with GNSS altitude to the second + // track + gnss_wpt = waypt_dupe(pres_wpt); + + if (gnss_alt) { + gnss_valid = 1; + gnss_wpt->altitude = gnss_alt; + } else { + gnss_wpt->altitude = unknown_alt; + } + route_add_wpt(gnss_head, gnss_wpt); + break; + + case rec_task: + // Create a route for each pre-flight declaration + igc_task_rec(ibuf); + break; + + case rec_log_book: + // Get the log book sub type + if (sscanf(ibuf, "L%3s", tmp_str) != 1) { + fatal(MYNAME ": log book (L) record parse error\n'%s'\n", ibuf); + } + + if (strcmp(tmp_str, "PFC") == 0) { + // Create a route for each post-flight declaration + igc_task_rec(ibuf + 4); + break; + } else if (global_opts.debug_level) { + if (strcmp(tmp_str, "OOI") == 0) { + fputs(MYNAME ": Observer Input> ", stdout); + } else if (strcmp(tmp_str, "PLT") == 0) { + fputs(MYNAME ": Pilot Input> ", stdout); + } else if (strcmp(tmp_str, manufacturer) == 0) { + fputs(MYNAME ": Manufacturer Input> ", stdout); + } else { + fputs(MYNAME ": Anonymous Input> ", stdout); + fputs(ibuf + 1, stdout); + break; + } + fputs(ibuf + 4, stdout); + putchar('\n'); + } + break; + + // These record types are discarded + case rec_diff_gps: + case rec_event: + case rec_constel: + case rec_security: + case rec_fix_defn: + case rec_extn_defn: + case rec_extn_data: + break; + + // No more records + case rec_none: + + // Include pressure altitude track only if it has useful + // altitude data or if it is the only track available. + if (pres_head && !pres_valid && gnss_head) { + track_del_head(pres_head); + pres_head = NULL; + } + // Include GNSS altitude track only if it has useful altitude + // data or if it is the only track available. + if (gnss_head && !gnss_valid && pres_head) { + track_del_head(gnss_head); + } + return; // All done so bail + + default: + case rec_bad: + fatal(MYNAME ": failure reading file\n"); + break; + } + } +} + +/************************************************************************************************* + * Output file processing + */ + +/************************************************* + * Callbacks used to scan for specific track types + */ + +static void detect_pres_track(const route_head * rh) +{ + if (rh->rte_name && strncmp(rh->rte_name, PRESTRKNAME, 6) == 0) { + head = rh; + } +} + +static void detect_gnss_track(const route_head * rh) +{ + if (rh->rte_name && strncmp(rh->rte_name, GNSSTRKNAME, 6) == 0) { + head = rh; + } +} + +static void detect_other_track(const route_head * rh) +{ + static int max_waypt_ct; + + if (!head) { + max_waypt_ct = 0; + } + // Find other track with the most waypoints + if (rh->rte_waypt_ct > max_waypt_ct && + (!rh->rte_name || + (strncmp(rh->rte_name, PRESTRKNAME, 6) != 0 && + strncmp(rh->rte_name, GNSSTRKNAME, 6) != 0))) { + head = rh; + max_waypt_ct = rh->rte_waypt_ct; + } +} + +/* + * Identify the pressure altitude and GNSS altitude tracks. + * @param pres_track Set by the function to the pressure altitude track + * head. NULL if not found. + * @param gnss_track Set by the function to the GNSS altitude track + * head. NULL if not found. + */ +static void get_tracks(const route_head ** pres_track, const route_head ** gnss_track) +{ + head = NULL; + track_disp_all(detect_pres_track, NULL, NULL); + *pres_track = head; + + head = NULL; + track_disp_all(detect_gnss_track, NULL, NULL); + *gnss_track = head; + + head = NULL; + track_disp_all(detect_other_track, NULL, NULL); + + if (!*pres_track && *gnss_track && head) { + *pres_track = head; + } + + if (!*gnss_track && head) { + *gnss_track = head; + } +} + +/************************************************* + * IGC string formatting functions + */ + +static char *latlon2str(const waypoint * wpt) +{ + static char str[18] = ""; + char lat_hemi = wpt->latitude < 0 ? 'S' : 'N'; + char lon_hemi = wpt->longitude < 0 ? 'W' : 'E'; + unsigned char lat_deg = fabs(wpt->latitude); + unsigned char lon_deg = fabs(wpt->longitude); + unsigned int lat_min = (fabs(wpt->latitude) - lat_deg) * 60000 + 0.5; + unsigned int lon_min = (fabs(wpt->longitude) - lon_deg) * 60000 + 0.5; + + if (snprintf(str, 18, "%02u%05u%c%03u%05u%c", + lat_deg, lat_min, lat_hemi, lon_deg, lon_min, lon_hemi) != 17) { + fatal(MYNAME ": Bad waypoint format '%s'\n", str); + } + return str; +} + +static char *date2str(struct tm *dt) +{ + static char str[7] = ""; + + if (snprintf(str, 7, "%02u%02u%02u", dt->tm_mday, dt->tm_mon + 1, dt->tm_year % 100) != 6) { + fatal(MYNAME ": Bad date format '%s'\n", str); + } + return str; +} + +static char *tod2str(struct tm *tod) +{ + static char str[7] = ""; + + if (snprintf(str, 7, "%02u%02u%02u", tod->tm_hour, tod->tm_min, tod->tm_sec) != 6) { + fatal(MYNAME ": Bad time of day format '%s'\n", str); + } + return str; +} + +/* + * Write header records + */ +static void wr_header(void) +{ + const route_head *pres_track; + const route_head *track; + struct tm *tm; + time_t date; + static const char dflt_str[] = "Unknown"; + const char *str; + waypoint *wpt; + + get_tracks(&pres_track, &track); + if (!track && pres_track) { + track = pres_track; + } + // Date in header record is that of the first fix record + date = !track ? current_time() : + ((waypoint *) QUEUE_FIRST(&track->waypoint_list))->creation_time; + + if (NULL == (tm = gmtime(&date))) { + fatal(MYNAME ": Bad track timestamp\n"); + } + xfprintf(MYNAME, file_out, "HFDTE%s\r\n", date2str(tm)); + + // Other header data may have been stored in track description + if (track && track->rte_desc && strncmp(track->rte_desc, HDRMAGIC, strlen(HDRMAGIC)) == 0) { + for (str = strtok(track->rte_desc + strlen(HDRMAGIC) + strlen(HDRDELIM), HDRDELIM); + str; str = strtok(NULL, HDRDELIM)) { + xfprintf(MYNAME, file_out, "%s\r\n", str); + } + } else { + // IGC header info not found so synthesise it. + // If a waypoint is supplied with a short name of "PILOT", use + // its description as the pilot's name in the header. + str = dflt_str; + if (NULL != (wpt = find_waypt_by_name("PILOT")) && wpt->description) { + str = wpt->description; + } + xfprintf(MYNAME, file_out, "HFPLTPILOT:%s\r\n", str); + } +} + +/************************************************* + * Generation of IGC task declaration records + */ + +static void wr_task_wpt_name(const waypoint * wpt, const char *alt_name) +{ + xfprintf(MYNAME, file_out, "C%s%s\r\n", latlon2str(wpt), + wpt->description ? wpt->description : wpt->shortname ? wpt->shortname : alt_name); +} + +static void wr_task_hdr(const route_head * rte) +{ + unsigned char have_takeoff = 0; + const waypoint *wpt; + char flight_date[7] = "000000"; + char task_desc[MAXRECLEN] = ""; + int num_tps = rte->rte_waypt_ct - 2; + struct tm *tm; + time_t rte_time; + static unsigned int task_num = 1; + + if (num_tps < 0) { + fatal(MYNAME ": Empty task route\n"); + } + // See if the takeoff and landing waypoints are there or if we need to + // generate them. + wpt = (waypoint *) QUEUE_LAST(&rte->waypoint_list); + if (wpt->shortname && strncmp(wpt->shortname, "LANDING", 6) == 0) { + num_tps--; + } + wpt = (waypoint *) QUEUE_FIRST(&rte->waypoint_list); + if (wpt->shortname && strncmp(wpt->shortname, "TAKEOFF", 6) == 0) { + have_takeoff = 1; + num_tps--; + } + if (num_tps < 0) { + fatal(MYNAME ": Too few waypoints in task route\n"); + } + // Gather data to write to the task identification (first) record + rte_time = wpt->creation_time ? wpt->creation_time : current_time(); + if (NULL == (tm = gmtime(&rte_time))) { + fatal(MYNAME ": Bad task route timestamp\n"); + } + + if (rte->rte_desc) { + sscanf(rte->rte_desc, DATEMAGIC "%6[0-9]: %s", flight_date, task_desc); + } + + xfprintf(MYNAME, file_out, "C%s%s%s%04u%02u%s\r\n", date2str(tm), + tod2str(tm), flight_date, task_num++, num_tps, task_desc); + + if (!have_takeoff) { + // Generate the takeoff waypoint + wr_task_wpt_name(wpt, "TAKEOFF"); + } +} + +static void wr_task_wpt(const waypoint * wpt) +{ + wr_task_wpt_name(wpt, ""); +} + +static void wr_task_tlr(const route_head * rte) +{ + // If the landing waypoint is not supplied we need to generate it. + const waypoint *wpt = (waypoint *) QUEUE_LAST(&rte->waypoint_list); + if (!wpt->shortname || strncmp(wpt->shortname, "LANDIN", 6) != 0) { + wr_task_wpt_name(wpt, "LANDING"); + } +} + +static void wr_tasks(void) +{ + route_disp_all(wr_task_hdr, wr_task_tlr, wr_task_wpt); +} + +/* + * Write a single fix record + */ +static void wr_fix_record(const waypoint * wpt, int pres_alt, int gnss_alt) +{ + struct tm *tm; + + if (NULL == (tm = gmtime(&wpt->creation_time))) { + fatal(MYNAME ": bad track timestamp\n"); + } + + if (unknown_alt == pres_alt) { + pres_alt = 0; + } + if (unknown_alt == gnss_alt) { + gnss_alt = 0; + } + xfprintf(MYNAME, file_out, "B%02u%02u%02u%sA%05d%05d\r\n", tm->tm_hour, + tm->tm_min, tm->tm_sec, latlon2str(wpt), pres_alt, gnss_alt); +} + +/** + * Attempt to align the pressure and GNSS tracks in time. + * This is useful when trying to merge a track (lat/lon/time) recorded by a + * GPS with a barograph (alt/time) recorded by a seperate instrument with + * independent clocks which are not closely synchronised. + * @return The number of seconds to add to the GNSS track in order to align + * it with the pressure track. + */ +static int correlate_tracks(const route_head * pres_track, const route_head * gnss_track) +{ + const queue *elem; + double last_alt, alt_diff; + double speed; + time_t pres_time, gnss_time; + int time_diff; + const waypoint *wpt; + + // Deduce the landing time from the pressure altitude track based on + // when we last descended to within 10m of the final track altitude. + elem = QUEUE_LAST(&pres_track->waypoint_list); + last_alt = ((waypoint *) elem)->altitude; + do { + elem = elem->prev; + if (&pres_track->waypoint_list == elem) { + // No track left + return 0; + } + alt_diff = last_alt - ((waypoint *) elem)->altitude; + if (alt_diff > 10.0) { + // Last part of track was ascending + return 0; + } + } while (alt_diff > -10.0); + pres_time = ((waypoint *) elem->next)->creation_time; + if (global_opts.debug_level >= 1) { + printf(MYNAME ": pressure landing time %s", ctime(&pres_time)); + } + // Deduce the landing time from the GNSS altitude track based on + // when the groundspeed last dropped below a certain level. + elem = QUEUE_LAST(&gnss_track->waypoint_list); + last_alt = ((waypoint *) elem)->altitude; + do { + wpt = (waypoint *) elem; + elem = elem->prev; + if (&gnss_track->waypoint_list == elem) { + // No track left + return 0; + } + // Get a crude indication of groundspeed from the change in lat/lon + time_diff = wpt->creation_time - ((waypoint *) elem)->creation_time; + speed = !time_diff ? 0 : + (fabs(wpt->latitude - ((waypoint *) elem)->latitude) + + fabs(wpt->longitude - ((waypoint *) elem)->longitude)) / time_diff; + if (global_opts.debug_level >= 2) { + printf(MYNAME ": speed=%f\n", speed); + } + } while (speed < 0.00003); + gnss_time = ((waypoint *) elem->next)->creation_time; + if (global_opts.debug_level >= 1) { + printf(MYNAME ": gnss landing time %s", ctime(&gnss_time)); + } + // Time adjustment is difference between the two estimated landing times + if (15 * 60 < abs(time_diff = pres_time - gnss_time)) { + warning(MYNAME ": excessive time adjustment %ds\n", time_diff); + } + return time_diff; +} + +/** + * Interpolate altitude from a track at a given time. + * @param track The track containing altitude data. + * @param time The time that we are interested in. + * @return The altitude interpolated from the track. + */ +static double interpolate_alt(const route_head * track, time_t time) +{ + static const queue *prev_elem = NULL; + static const queue *curr_elem = NULL; + const waypoint *prev_wpt; + const waypoint *curr_wpt; + int time_diff; + double alt_diff; + + // Start search at the beginning of the track + if (!prev_elem) { + curr_elem = prev_elem = QUEUE_FIRST(&track->waypoint_list); + } + // Find the track points either side of the requested time + while (((waypoint *) curr_elem)->creation_time < time) { + if (QUEUE_LAST(&track->waypoint_list) == curr_elem) { + // Requested time later than all track points, we can't interpolate + return unknown_alt; + } + prev_elem = curr_elem; + curr_elem = QUEUE_NEXT(prev_elem); + } + + prev_wpt = (waypoint *) prev_elem; + curr_wpt = (waypoint *) curr_elem; + + if (QUEUE_FIRST(&track->waypoint_list) == curr_elem) { + if (curr_wpt->creation_time == time) { + // First point's creation time is an exact match so use it's altitude + return curr_wpt->altitude; + } else { + // Requested time is prior to any track points, we can't interpolate + return unknown_alt; + } + } + // Interpolate + if (0 == (time_diff = curr_wpt->creation_time - prev_wpt->creation_time)) { + // Avoid divide by zero + return curr_wpt->altitude; + } + alt_diff = curr_wpt->altitude - prev_wpt->altitude; + return prev_wpt->altitude + (alt_diff / time_diff) * (time - prev_wpt->creation_time); +} + +/* + * Pressure altitude and GNSS altitude may be provided in two seperate + * tracks. This function attempts to merge them into one. + */ +static void wr_track(void) +{ + const route_head *pres_track; + const route_head *gnss_track; + const waypoint *wpt; + const queue *elem; + const queue *tmp; + int time_adj; + double pres_alt; + + // Find pressure altitude and GNSS altitude tracks + get_tracks(&pres_track, &gnss_track); + + // If both found, attempt to merge them + if (pres_track && gnss_track) { + if (timeadj) { + if (strcmp(timeadj, "auto") == 0) { + time_adj = correlate_tracks(pres_track, gnss_track); + } else if (sscanf(timeadj, "%d", &time_adj) != 1) { + fatal(MYNAME ": bad timeadj argument '%s'\n", timeadj); + } + } else { + time_adj = 0; + } + if (global_opts.debug_level >= 1) { + printf(MYNAME ": adjusting time by %ds\n", time_adj); + } + // Iterate through waypoints in both tracks simultaneously + QUEUE_FOR_EACH(&gnss_track->waypoint_list, elem, tmp) { + wpt = (waypoint *) elem; + pres_alt = interpolate_alt(pres_track, wpt->creation_time + time_adj); + wr_fix_record(wpt, pres_alt, wpt->altitude); + } + } else { + if (pres_track) { + // Only the pressure altitude track was found so generate fix + // records from it alone. + QUEUE_FOR_EACH(&pres_track->waypoint_list, elem, tmp) { + wr_fix_record((waypoint *) elem, ((waypoint *) elem)->altitude, unknown_alt); + } + } else if (gnss_track) { + // Only the GNSS altitude track was found so generate fix + // records from it alone. + QUEUE_FOR_EACH(&gnss_track->waypoint_list, elem, tmp) { + wr_fix_record((waypoint *) elem, unknown_alt, ((waypoint *) elem)->altitude); + } + } else { + // No tracks found so nothing to do + return; + } + } +} + +static void wr_init(const char *fname) +{ + file_out = xfopen(fname, "wb", MYNAME); +} + +static void wr_deinit(void) +{ + fclose(file_out); +} + +static void data_write(void) +{ + xfputs(MYNAME, "AXXXZZZGPSBabel\r\n", file_out); + wr_header(); + wr_tasks(); + wr_track(); + xfprintf(MYNAME, file_out, "LXXXGenerated by GPSBabel Version %s\r\n", gpsbabel_version); + xfputs(MYNAME, "GGPSBabelSecurityRecordGuaranteedToFailVALIChecks\r\n", file_out); +} + + +static arglist_t igc_args[] = { + {"timeadj", &timeadj, + "(integer sec or 'auto') Barograph to GPS time diff", + NULL, ARGTYPE_STRING}, + {0, 0, 0, 0, 0} +}; + +ff_vecs_t igc_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL, + igc_args +}; diff --git a/intdoc/BraunigerIQformat b/intdoc/BraunigerIQformat new file mode 100644 index 000000000..8dd5d2853 --- /dev/null +++ b/intdoc/BraunigerIQformat @@ -0,0 +1,55 @@ +The following description was provided courtesy of the guys at Brauniger, +translated from German by Google: + + + +IQ-GPS PC data communication +============================ +Description of the sequence for the transmission of barograms IQ-GPS over the +serial interface (9600 Baud, 8, NO parity): + +All values are binary coded, with exception of the Pilot names. + +* 48, 49, 50, 51, 52, 53 (to the synchronisation) +* 1 byte flight number +* high and low - byte of the number of still following bytes +* high and low - byte of the serial number +* 25 byte pilot name (ASCII) +* high and low - byte of the starting date (e.g. 1309 for 13.09) +* high and low - byte of the starting year (e.g. 1995) +* high and low - byte of the maximum height 1 +* high and low - byte of the maximum height 2 +* high and low - byte of the maximum rise +* high and low - byte of the flying time in minutes +* 1 byte for the logging period (e.g. 5 for 5 seconds) +* high and low - byte of the starting time (e.g. 1105 for 11:05) +* high and low - byte of the stop time (e.g. 1305 for 13:05) + * for future extensions: 2 polar coordinates follow: + * Sinking value 1 (e.g. 10 = -1.0m/s) + * Speed value 1 (km/h) + * Sinking value 2 + * Speed value 2 + * 12 GPS coordinate values, binary coded as 4 byte long variable, follow + negative value mean W (S), positive value mean E (N). 0x00000000 if no + marking set was set, for 0xFFFFFFFF if marking, but no valid position. + * 4 byte Longitude 1 (MSB first) + * 4 byte Latitude 1 (MSB first) + ... + * 4 byte Longitude 12 (MSB first) + * 4 byte Latitude 12 (MSB first) +* now all heights and velocity values in the order: 2 byte for the height, 1 + byte for speed. Markings are coded in the height with an offset of 20.000 m. + + +Leimkuhler 18.02.99 + + + +I'm not sure about the "future extensions" part. My IQ-Competition/GPS doesn't +spit out those values and I believe that it has the most recent firmware. + +Also, curiously the final height/speed pair consistently omits the speed part. + + +Chris Jones +Aug 2004 diff --git a/intdoc/MPSformat b/intdoc/MPSformat new file mode 100644 index 000000000..cc1100fa9 --- /dev/null +++ b/intdoc/MPSformat @@ -0,0 +1,382 @@ +// An EBNF+ format. + +// This is a comment +// "xxx" is the literal three characters x, x and x +// 0xA8 means a byte of hexadecimal value A8 +// ::= 0x00 +// FunctionName() means the result of FunctionName when executed on parameter +// FunctionName ::= defines the result format in a text description +// [] means is optional +// | means either or +// { } is grouping of two or more entities together; mainly for use with the | or operator +// Entity names might be long winded but are intended to convey some meaning without explicit/additional comments + +// Version history +// V2.5 - 2004/01/12 20:49 GMT mrcb.mps.fmt@osps.net +// Updates to record signatures for MapSource V5.3 & 5.4 +// Update to incorporate the sketchiest of subclass details +// V2.4 - 2003/10/18 18:42 BST (GMT+1) mrcb.mps.fmt@osps.net +// Updates to route formats to include interlink steps (my name for them) +// V2.3 - 2003/10/03 17:49 BST (GMT+1) mrcb.mps.fmt@osps.net +// I must type really badly as there were more typoes to sort out. +// V2.2 - 2003/09/27 23:33 BST (GMT+1) mrcb.mps.fmt@osps.net +// Corrected typoes +// Corrected NULL terminated string length counts for records with strings +// V2.1 - 2003/09/12 18:23 BST (GMT+1) mrcb.mps.fmt@osps.net +// Changed some of the expressions covering the sections so that the LengthOf(x) was a less ambiguous x +// Corrected some typoes +// Added definitions of MapSource V5.0 (this creates data files of format 1.05, apparently) +// +// V2.0 - 2003/07/15 21:34 BST (GMT+1) mrcb.mps.fmt@osps.net +// Complete definitions as far as possible (in my ability, anyway) for V3.02 formats. +// Some typoes cleaned up. +// Replaced "unknown" by "UNKNOWN" in entity names where the meaning is not known to this author +// (as opposed to, for example, where the meaning is known but the value happens to be "unknown", +// as in the colour unknown). +// Added definitions for V5.03beta of MapSource - no seeming significant changes from v4 - woopee. +// +// V1.0 - 2003/06/30 21:00 BST mrcb.mps.fmt@osps.net +// First "release". Coverage for version 4.xx (to 4.13) is good although some unknowns still +// Coverage for V3.x is less good since it seems a little needless to document a format no longer +// in use, so why start to? Good question. Perhaps I'll finish it off when my MapSource 3 machine +// is fixed. + + +// Start of MapSource definition ================================================== + ::=
[] [] [] [] + +
::= + + ::= "MsRc" + + ::= + + ::= "d" + + ::= LengthOf() + + ::= "D" + + ::= | + | + | + | + | + | + + + ::= "d" + ::= "g" + ::= "h" + ::= "i" + ::= "i" + ::= "i" + ::= "i" + + ::= LengthOf() + + ::= "A" + + ::= | + | + | + | + | + | + + +// Perhaps this is software build number + ::= 0x2E 0x01 + ::= 0x96 0x01 + ::= 0x9D 0x01 + ::= 0xF4 0x01 + ::= 0xF4 0x01 + ::= 0xF7 0x01 + ::= 0xF8 0x01 + +// SQA might be Software Quality Assurance; buell appears in the beta, so is presumably the programmer's id + ::= "SQA" | "buell" + + ::= | + | + | + | + | + | + + + ::= "Oct 20 1999" "12:50:03" + ::= "Oct 22 2001" "15:45:05" + ::= "Mar 7 2003" "15:12:28" + ::= "Jun 27 2003" "10:12:10" + ::= "Jul 3 2003" "08:35:39" + ::= "Sep 24 2003" "11:44:25" + ::= "Nov 6 2003" "16:01:32" + + ::= LengthOf() + + ::= "V" ASCII-Map-Set-Name-can-be-blank + + ::= | + ::= 0x00 + ::= 0x01 + +// ............................ + ::= + + ::= LengthOf() [] + + ::= | | + + ::= "W" + + + + + ::= x-character-short-name + + ::= Long(class) +// Class classification - cf D154_Wpt_Type +// 0 = user waypoint, editable +// 1 = Airport, not user editable +// 2 = Aviation Intersection, not user editable +// 3 = NDB (whatever that is), not user editable +// 4 = VOR, not user editable +// 5 = Runway Threshold, not user editable +// 6 = Airport Intersection, not user editable +// 7 = Airport NDM, not user editable +// 8 = Map Point, not user editable +// 9 = Map Area, not user editable +// A = Map Intersection, not user editable +// B = Map Address, not user editable +// C = Map Line, not user editable + +// Valid for waypoint class types 1 to 8 + ::= country-string + +// Perhaps some waypoint subclass definition? +// The following almost certainly contains - this is the case for the V4 formatted file +// Vwip - added 0x00 at the end of this + ::= 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 + + ::= ASCII-Character-string + + ::= + + ::= | | + + ::= Long(0x00) + ::= Long(0x01) + ::= Long(0x02) + + ::= + + ::= Long() + +// Next three only valid for waypoint classes 1 to 8 + ::= city-string + ::= USA-state-for-waypoint-city-string + ::= facility-string + + ::= + + ::= 2-bytes-unknown + + ::= "W" + + + + + +// Values depend on . If class is zero, then +// subclass = 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF +// (last two octects may be zero depending on whether the waypoint was originally created +// in MapSource V3) +// If class is non-zero, then values are unknown + ::= 18-bytes-unknown + + ::= 0xFF 0xFF 0xFF 0xFF + +// Perhaps the 2 bytes of plus Field-defined-flag plus a Long value + ::= 7-bytes-unknown + + ::= + +// ............................ + ::= + + ::= LengthOf() [] + + ::= | | + +// Note: for each waypoint that appears in a route, there must also be a "normal" waypoint defined + ::= "R" ASCII-Route-Name-string + Long(Number-of-Waypoints-in-Route) + +// Note: for each waypoint that appears in a route, there must also be a "normal" waypoint defined + ::= "R" ASCII-Route-Name-string + Long(Number-of-Waypoints-in-Route) + + ::= + + ::= | + ::= Word(0x00) + ::= Word(0x01) + +// Max values taken from all waypoints in the route to form a virtual "upper right" point + ::= + +// Part of the route bounding a 3D co-ordinate + ::= + +// Min values taken from all waypoints in the route to form a virtual "lower left" point + ::= + +// Part of the route bounding a 3D co-ordinate + ::= + + ::= Long(0x00) 0x01 + + ::= [] + + ::= + + ::= ASCII-name + +// The first zero seems to be a string terminator + ::= 0x00 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 + + ::= Long(0x00) 0x01 + + ::= [] + + ::= + + + ::= empty-if-class-is-zero | 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF + +// The first zero seems to be a string terminator + ::= 0x00 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 + + ::= Long(0x02 + Num-of-Interlink-steps) [] + + +// These are optional additional steps between the two ends of the link +// Why MapSource creates these is unknown + ::= + + ::= + + ::= + +// Virtual "Upper right top" co-ordinate + ::= + +// Virtual "lower left bottom" co-ordinate + ::= + + ::= + +// ............................ + ::= + + ::= LengthOf() [] + + ::= | | + + ::= "T" ASCII-Tracklog-Name-string + Long(Number-of-datapoints-in-tracklog) + + ::= + + ::= + + ::= | + ::= 0x01 + ::= 0x00 + + ::= + + ::= [] [] + + ::== + +// ............................ + ::= + + ::= LengthOf() [] + + ::= | | + +// Map segments are portions of the overall map +// What is stored in the MPS file is not the map detail but references to the detail +// Area name refers to an area larger than the segment, perhaps by way of locating the segment within the World + ::= "L" Long(Map-CD-ID) Long(Segment-ID) ASCII-CD-Name ASCII-Segment-Name ASCII-Area-Name Long(0x00) + + ::= + + ::= + +// Common definitions -------------------------------------------------------------- + + ::= | | | colour dark green> | | | + | | | | | + | | | | + ::= Long(0x00) + ::= Long(0x01) + ::= Long(0x02) + ::= Long(0x03) + ::= Long(0x04) + ::= Long(0x05) + ::= Long(0x06) + ::= Long(0x07) + ::= Long(0x08) + ::= Long(0x09) + ::= Long(0x0A) + ::= Long(0x0B) + ::= Long(0x0C) + ::= Long(0x0D) + ::= Long(0x0E) + ::= Long(0x0F) + ::= Long(0x10) + + ::= + + ::= Double(Value in metres) + + ::= + + ::= Long(date-time-seconds-since-00:00:00-01/01/1970) + + ::= + +// Depth is not negative altitude - GPS not being overly useful on a submarine - but the "thickness" of a GPS point (e.g. airspace) +// Assumed to be calculated below the GPS datapoint height. If so, then the object being referenced extends from +// (Altitude - depth) to (Altitude) upwards + ::= Double(value in metres) + + ::= + + ::= Double(Value in metres) + + ::= | + ::= 0x01 + ::= 0x00 + +// Check out the values in the Garmin Protocol description document and elsewhere on the web + ::= Too-many-to-list-here-! + + ::= Long(latitude * 2^31 / 180) + ::= Long(longitude * 2^31 / 180) + +// Start of function definitions --------------------------------------------------- +Word ::= 2 bytes, little endian +Long ::= 4 bytes, little endian +Double ::= 8 byte, little endian, IEEE format +LengthOf ::= 4 bytes, little endian - zero value means "1 element long" +// End of function definitions + +// End of MapSource defintion + diff --git a/intdoc/SA2003_annotations.txt b/intdoc/SA2003_annotations.txt new file mode 100644 index 000000000..6cea4454d --- /dev/null +++ b/intdoc/SA2003_annotations.txt @@ -0,0 +1,419 @@ +This is an annotated hex dump of a Street Atlas 2003 .anr file. +I've also added notes to indicate where SA 2005 puts extra data + + 2D 32 magic + 07 00 version + 02 00 00 00 unknown + 01 00 00 00 unknown (version 7+ only) + 01 00 00 00 unknown (version 7+ only) + +-- end of header -- + + 0A 00 record type? + 44 00 00 00 record size - strlen + 20 04 0F 11 ??? + 01 00 00 00 ??? + 01 00 00 00 ??? + 01 00 00 00 ??? + 00 00 00 00 ??? + 00 00 ??? + 14 40 00 00 ??? + 15 00 strlen of route name + 68 6F 6D 65 20 74 6F 20 77 6F 72 6B 20 62 61 63 6B 20 77 61 79 + route name (home to work back way) + 00 00 ??? + 29 5C 8F C2 F5 28 05 40 = 2.645000 (distance in km) + 6B 01 00 00 = 363 = 6:03 (total time) + 07 A8 35 6F 7B 03 69 40 = 200.108818 (overall heading) + 79 29 0F 3F ??? = 0.559227 + 98 38 0F 3F ??? = 0.559457 + 20 00 00 00 ??? + 01 00 ??? + +-- end of routefile header -- + + 03 00 00 00 count + + 01 00 type? + 64 00 00 00 size + E9 F0 6B 55 lon 85.1567105054855 (actual point) + 84 43 6C 6B lat 41.1542053222656 + 11 04 82 08 + 30 04 0F 11 + 13 00 00 00 (19) + 16 00 strlen of address + 38 30 32 35 20 53 69 6C 76 65 72 20 53 70 72 69 6E 67 73 20 50 6C address (8025 Silver Springs Pl) + 16 00 strlen of comment + 38 30 32 35 20 53 69 6C 76 65 72 20 53 70 72 69 6E 67 73 20 50 6C comment (8025 Silver Springs Pl) + 02 00 START? + 9B FF FF FF (-101) + 9B FF FF FF (-101) + 01 00 + 7B F4 6B 55 lon 85.1566015481949 (point on closest road) + B3 43 6C 6B lat 41.1541839838028 + 14 00 00 00 (20) + 14 00 00 00 (20) + 00 00 00 00 +------------ + 00 00 00 00 + 00 00 00 00 +------------ + 01 00 type? + 4E 00 00 00 size + 8A B7 6B 55 lon 85.1584613323212 (actual point) + 9D 65 6C 6B lat 41.1531490087509 + 13 04 82 08 + 30 04 0F 11 + 1D 00 00 00 (29) + 0B 00 strlen of address + 4D 61 79 66 69 65 6C 64 20 50 6C address (Mayfield Pl) + 0B 00 strlen of comment + 4D 61 79 66 69 65 6C 64 20 50 6C comment (Mayfield Pl) + 01 00 VIA? + 9B FF FF FF + 9B FF FF FF + 01 00 + 93 B7 6B 55 lon 85.1584602594376 (point on closest road) + 46 65 6C 6B lat 41.1531593799591 + 14 00 00 00 + 14 00 00 00 + 00 00 00 00 +------------ + 00 00 00 00 + 00 00 00 00 +------------ +SA 2005 contains something like this here: + 00 00 00 00 + 00 00 + F0 BF 00 00 + 00 00 00 00 + F0 BF 00 00 +------------ + 01 00 type? + 72 00 00 00 size + F3 72 6B 55 lon 85.1605545282364 (actual point) + E2 4D 6D 6B lat 41.1460607051849 / + 15 04 82 08 + 30 04 0F 11 + 18 00 00 00 ??? (24) + 1D 00 strlen of address + 37 32 35 20 41 69 72 70 6F 72 74 20 4E 6F 72 74 68 20 4F 66 66 69 63 65 20 50 61 72 6B + address (725 Airport North Office Park) + 1D 00 strlen of comment + 37 32 35 20 41 69 72 70 6F 72 74 20 4E 6F 72 74 68 20 4F 66 66 69 63 65 20 50 61 72 6B + comment (725 Airport North Office Park) + 03 00 STOP? + 9B FF FF FF ??? (-101) + 9B FF FF FF ??? (-101) + 01 00 Is this a count of latlon points to follow? Should I worry? + D2 71 6B 55 lon 85.1605889797211 (point on closest road) + 71 50 6D 6B lat 41.1459826231003 / + 14 00 00 00 ??? (20) + 14 00 00 00 ??? (20) + 00 00 00 00 ??? (0) +------------ + 00 00 00 00 + 00 00 00 00 +------------ +SA 2005 contains something like this here: + 00 00 00 00 + 00 00 + F0 BF 00 00 + 00 00 00 00 + F0 BF 00 00 +------------ beginning of route coordinates + 01 00 00 00 route leg count +------------ beginning of leg 1 + 0A 00 type? + 32 00 00 00 size + 00 00 00 00 ??? + 1F 00 00 00 ??? + 00 00 ??? + 06 00 00 00 ??? + 04 00 00 00 ??? + 29 5C 8F C2 F5 28 05 40 2.645000 (distance in km) + 6B 01 00 00 363 = 6:03 (total time) + 07 A8 35 6F 7B 03 69 40 200.108818 (overall heading) + 00 00 00 00 ??? always? 0 + 00 00 00 00 ??? always? 0 + 00 00 00 00 ??? always? 0 +------------ + 0B 00 00 00 leg segment count +------------ 1 SS Pl + 0A 00 type? + 61 00 00 00 size + 11 00 strlen of street + 53 69 6C 76 65 72 20 53 70 72 69 6E 67 73 20 50 6C street (Silver Springs Pl) + 09 00 00 00 road type (local road) + 01 00 00 00 ??? seems to be 0 or 1 + DB F9 7E 6A BC 74 93 3F = .019 length (km) + 02 00 00 00 end time + 06 00 00 00 ??? + 56 F3 93 DD A6 FD 66 40 = 183.927 heading (degrees) + 00 00 00 00 ??? always? 0 + 00 00 00 00 ??? always? 0 + 00 00 00 00 ??? always? 0 + 00 00 00 00 ??? usually -1, but on first record it seems to be 0 + 00 00 00 00 transit time + 00 00 00 00 00 00 00 00 = 0.00 distance at start (km) + 02 00 coord pair count + B3 43 6C 6B \ + 7B F4 6B 55 \ coord + 50 49 6C 6B / pairs + F8 F3 6B 55 / +------------ +SA 2005 contains something like this here (and at the end of every leg; I haven't pasted them anywhere else): + 07 00 00 00 + 00 00 00 00 +------------ 2 SS Ct + 0A 00 + 61 00 00 00 + 11 00 + 53 69 6C 76 65 72 20 53 70 72 69 6E 67 73 20 43 74 + 09 00 00 00 road type (local road) + 01 00 00 00 + FC A9 F1 D2 4D 62 B0 3F = .064 length (km) + 09 00 00 00 end time + 00 00 00 00 + 29 C8 2B 53 7B 9C 70 40 = 265.780 heading (degrees) + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + FF FF FF FF + 02 00 00 00 transit time + DB F9 7E 6A BC 74 93 3F = 0.019 distance at start (km) + 02 00 + 50 49 6C 6B + F8 F3 6B 55 + B8 4A 6C 6B + A8 DA 6B 55 +------------ 3 SS Run + 0A 00 + 62 00 00 00 + 12 00 + 53 69 6C 76 65 72 20 53 70 72 69 6E 67 73 20 52 75 6E + 09 00 00 00 road type (local road) + 01 00 00 00 + 11 58 39 B4 C8 76 BE 3F = .119 length (km) + 11 00 00 00 end time + 02 00 00 00 + 7B D1 CA 13 65 7C C5 3E = 0.000003 heading (degrees) + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + FF FF FF FF + 0B 00 00 00 transit time + 73 68 91 ED 7C 3F B5 3F = .083 distance at start (km) + 02 00 + B8 4A 6C 6B + A8 DA 6B 55 + 90 27 6C 6B + A8 DA 6B 55 +------------ 4 Oak Bay Run + 0A 00 + 63 00 00 00 + 0B 00 + 4F 61 6B 20 42 61 79 20 52 75 6E + 09 00 00 00 road type (local road) + 01 00 00 00 + 06 81 95 43 8B 6C D7 3F = 0.366000 length (km) + 36 00 00 00 end time + 00 00 00 00 + EC 69 A6 26 E4 F7 70 40 = 271.493201 heading (degrees) + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + FF FF FF FF + 1C 00 00 00 transit time + 42 60 E5 D0 22 DB C9 3F = 0.202000 distance at start (km) + 03 00 + 90 27 6C 6B + A8 DA 6B 55 + 90 27 6C 6B + C8 C9 6B 55 + C0 24 6C 6B + 38 4B 6B 55 +------------ 5 Northland + 0A 00 + 66 00 00 00 + 0E 00 + 4E 6F 72 74 68 6C 61 6E 64 20 42 6C 76 64 + 09 00 00 00 road type (local road) + 01 00 00 00 + 83 C0 CA A1 45 B6 D3 3F + 2D 00 00 00 + 00 00 00 00 + 64 6E 6C F9 04 E0 70 40 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + FF FF FF FF + 52 00 00 00 + 94 18 04 56 0E 2D E2 3F + 03 00 + C0 24 6C 6B + 38 4B 6B 55 + C0 24 6C 6B + 98 45 6B 55 + C0 24 6C 6B + 48 D2 6A 55 +------------ 6 SR 3 + 0A 00 + 5E 00 00 00 + 0E 00 + 53 52 20 33 20 28 4C 69 6D 61 20 52 64 29 + 03 00 00 00 road type (primary state/prov rte) + 00 00 00 00 + 23 DB F9 7E 6A BC C4 3F + 08 00 00 00 + 06 00 00 00 + C4 97 99 D0 11 7F 66 40 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + FF FF FF FF + 7F 00 00 00 + D6 78 E9 26 31 08 EC 3F + 02 00 + C0 24 6C 6B + 48 D2 6A 55 + 90 54 6C 6B + 48 D2 6A 55 +------------ 7 N Mayfield Pl + 0A 00 + 65 00 00 00 + 0D 00 + 4E 20 4D 61 79 66 69 65 6C 64 20 50 6C + 09 00 00 00 + 01 00 00 00 + 17 D9 CE F7 53 E3 C5 3F + 19 00 00 00 + 04 00 00 00 + 59 EC C0 84 35 5B 59 40 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + FF FF FF FF + 87 00 00 00 + CF F7 53 E3 A5 9B F0 3F + 03 00 + 90 54 6C 6B + 48 D2 6A 55 + 90 54 6C 6B + A0 F2 6A 55 + 68 5E 6C 6B + F8 12 6B 55 +------------ 8 Mayfield Pl + 0A 00 + 73 00 00 00 + 0B 00 + 4D 61 79 66 69 65 6C 64 20 50 6C + 09 00 00 00 + 01 00 00 00 + 87 16 D9 CE F7 53 DB 3F + 3F 00 00 00 + 04 00 00 00 + 13 45 4F 28 4E 4C 57 40 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + FF FF FF FF + A0 00 00 00 + F2 D2 4D 62 10 58 F3 3F + 05 00 + 68 5E 6C 6B + F8 12 6B 55 + 68 5E 6C 6B + 30 44 6B 55 + 46 65 6C 6B + 93 B7 6B 55 + 46 65 6C 6B + 93 B7 6B 55 + 70 65 6C 6B + 50 BA 6B 55 +------------ 9 Woodbine Ave + 0A 00 + 64 00 00 00 + 0C 00 + 57 6F 6F 64 62 69 6E 65 20 41 76 65 + 09 00 00 00 + 01 00 00 00 + 8D 97 6E 12 83 C0 E6 3F + 6A 00 00 00 + 06 00 00 00 + 8A C6 FD 0A AE 51 66 40 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + FF FF FF FF + DF 00 00 00 + 94 18 04 56 0E 2D FA 3F + 03 00 + 70 65 6C 6B + 50 BA 6B 55 + 00 8A 6C 6B + 50 BA 6B 55 + F8 36 6D 6B + 58 C1 6B 55 +------------ a W Cook Rd + 0A 00 + 59 00 00 00 + 09 00 + 57 20 43 6F 6F 6B 20 52 64 + 09 00 00 00 + 00 00 00 00 + CF F7 53 E3 A5 9B C4 3F + 0E 00 00 00 + 00 00 00 00 + 5B 80 08 FA F6 C4 70 40 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + FF FF FF FF + 49 01 00 00 + 2D B2 9D EF A7 C6 02 40 + 02 00 + F8 36 6D 6B + 58 C1 6B 55 + 60 38 6D 6B + 10 82 6B 55 +------------ b Airport North Office Park + 0A 00 + 79 00 00 00 + 19 00 + 41 69 72 70 6F 72 74 20 4E 6F 72 74 68 20 4F 66 66 69 63 65 20 50 61 72 6B + 09 00 00 00 + 01 00 00 00 + F0 A7 C6 4B 37 89 C1 3F + 14 00 00 00 + 07 00 00 00 + 7C E9 DD FE 17 DE 69 40 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + FF FF FF FF + 57 01 00 00 + AA F1 D2 4D 62 10 04 40 + 04 00 + 60 38 6D 6B + 10 82 6B 55 + 70 46 6D 6B + 10 82 6B 55 + 80 54 6D 6B + 10 82 6B 55 + 71 50 6D 6B + D2 71 6B 55 +------------ end of leg, end of route + 4C 00 00 00 record size + 42 60 E5 D0 22 9B 23 40 = 9.803000 + 00 00 00 00 00 00 E0 3F = 0.500000 + 9F AB AD D8 5F B6 46 40 = 45.424800 + 00 00 00 00 00 00 D0 3F = 0.250000 + 04 00 00 00 + 00 00 00 00 + 00 00 00 00 + 80 70 00 00 + 08 07 00 00 + 4C 37 89 41 60 25 89 40 = 804.672000 + 3D 2C D4 9A E6 1D 54 40 = 80.467200 + 02 00 00 00 diff --git a/intdoc/SA2005_dump.pl b/intdoc/SA2005_dump.pl new file mode 100644 index 000000000..e1c6fe765 --- /dev/null +++ b/intdoc/SA2005_dump.pl @@ -0,0 +1,156 @@ +#!/usr/bin/perl + +=pod + + This script reads a DeLorme Street Atlas 2003-2005 .anr (route) file + and prints various pertinent data from it. Anything with a variable + name starting with "unk" or "magic" or "zero" is probably something + we don't yet understand. Suggestions as to what some of these fields + mean are welcome. The author disclaims any liability arising from + the use of any information contained within this script. + + Copyright (C) 2004 Ronald L. Parker (babelanrperl@parkrrrr.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + +=cut + +# Convert a longword to a latitude or longitude +sub decode { + my $foo = shift; + + my $deg = (0x80000000-$foo)/(0x800000); + sprintf( "%d %06.3f", $deg, 60*($deg-int($deg))); +} + + +# read a data structure from the input file. +sub shiftunpack { + + my $pattern = shift; + my @result = unpack( $pattern, $file ); + my $str = pack( $pattern, @result ); + $file = substr( $file, length( $str )); + @result; +} + +# read file +undef $/; +$file = <>; + +# read file header +($magic, $version, $unk1, $unk2, $unk3) = shiftunpack( 'sslll' ); + +print < 10); + + print "$addr ($comment)\n ". + decode($actual_lat).' '.decode($actual_lon)."\n ". + decode($closest_lat).' '.decode($closest_lon)."\n"; + +} + +($routelegcount) = shiftunpack('l'); + +for ( 1..$routelegcount ) { + + # read leg header + ($type, $size, $unk1, $unk2, $unk3, $unk4, $unk5, + $distance, $time, $heading, $unk6, $unk7, $unk8) = + shiftunpack( 'slllslldldlll' ); + print "leg length $distance ($time seconds, $heading°)\n"; + + # read segment count + ($segcount)=shiftunpack('l'); + # read segments + for (1..$segcount) { + ($type, $size, $street, $roadtype, $unk1, + $distance, $transittime, $unk2, + $heading, $unk3, $unk4, $unk5, $unk6, + $starttime, $startdist, $coords) = + shiftunpack( 'sls/A*lldlldlllllds' ); + print "$street ($roadtype) distance $distance heading $heading\n starting $startdist [$starttime $transittime]\n"; + @coordpairs = shiftunpack( "(ll)[$coords]" ); + + for $c (0..$coords-1) { + print ' '.decode($coordpairs[$c*2]).' '.decode($coordpairs[$c*2+1])."\n"; + } + @SA2005Extras = shiftunpack('ll') if ($version > 10) ; + } +} + +# read footer +($size,$f1,$f2,$f3,$f4,$unk1,$unk2, $unk3,$unk4,$unk5,$f5,$f6,$unk6)= + shiftunpack('lddddlllllddl'); +printf( "%12.6f %12.6f %12.6f %12.6f %12.6f %12.6f\n", $f1, $f2, $f3, $f4, $f5, $f6); diff --git a/internal_styles.c b/internal_styles.c new file mode 100644 index 000000000..3b31cde74 --- /dev/null +++ b/internal_styles.c @@ -0,0 +1,559 @@ +/* This file is machine-generated from the contents of style/ */ +/* by mkstyle.sh. Editing it by hand is an exeedingly bad idea. */ + +static char arc[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: GPSBabel arc filter format\n" +"# Author: Ron Parker\n" +"# Date: 17 July 2003\n" +"#\n" + +"DESCRIPTION GPSBabel arc filter file\n" +"EXTENSION txt\n" + +"#\n" +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER TAB\n" +"RECORD_DELIMITER NEWLINE\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"IFIELD LAT_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD LON_DECIMAL, \"\", \"%08.5f\"\n" +; +static char csv[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: Delorme SA 9.0 CSV\n" +"# Author: Alex Mottram\n" +"# Date: 12/09/2002\n" +"#\n" +"# \n" +"DESCRIPTION Comma separated values\n" +"SHORTLEN 8\n" +"#\n" +"#\n" +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER COMMASPACE\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS COMMA\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"IFIELD LAT_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD LON_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD DESCRIPTION, \"\", \"%s\"\n" +; +static char custom[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: Custom \"Everything\" Style\n" +"# Author: Alex Mottram\n" +"# Date: 11/24/2002\n" +"#\n" +"#\n" + +"DESCRIPTION Custom \"Everything\" Style\n" + +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER COMMA\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS COMMA\n" +"FORMAT_TYPE INTERNAL\n" + +"#\n" +"# HEADER STUFF:\n" +"#\n" +"PROLOGUE Prologue Line 1 __FILE__\n" +"PROLOGUE Prologue Line 2\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS:\n" +"#\n" +"IFIELD CONSTANT, \"\", \"CONSTANT\"\n" +"IFIELD INDEX, \"\", \"%d\"\n" +"IFIELD LAT_DECIMAL, \"\", \"%f\"\n" +"IFIELD LAT_DIR, \"\", \"%c\"\n" +"IFIELD LON_DECIMAL, \"\", \"%f\"\n" +"IFIELD LON_DIR, \"\", \"%c\"\n" +"IFIELD ICON_DESCR, \"\", \"%s\"\n" +"IFIELD SHORTNAME, \"\", \"%s\"\n" +"IFIELD DESCRIPTION, \"\", \"%s\"\n" +"IFIELD NOTES, \"\", \"%s\"\n" +"IFIELD URL, \"\", \"%s\" \n" +"IFIELD URL_LINK_TEXT, \"\", \"%s\"\n" +"IFIELD ALT_METERS, \"\", \"%fM\"\n" +"IFIELD ALT_FEET, \"\", \"%fF\"\n" +"IFIELD LAT_DECIMALDIR, \"\", \"%f/%c\"\n" +"IFIELD LON_DECIMALDIR, \"\", \"%f/%c\"\n" +"IFIELD LAT_DIRDECIMAL, \"\", \"%c/%f\"\n" +"IFIELD LON_DIRDECIMAL, \"\", \"%c/%f\"\n" +"IFIELD LAT_INT32DEG, \"\", \"%ld\"\n" +"IFIELD LON_INT32DEG, \"\", \"%ld\"\n" +"IFIELD TIMET_TIME, \"\", \"%ld\"\n" +"IFIELD EXCEL_TIME, \"\", \"%f\"\n" + +"# EPILOGUE: \n" +"EPILOGUE Epilogue Line 1\n" +"EPILOGUE Epilogue Line 2\n" +; +static char dna[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: DNA Marker Format\n" +"# Author: Alex Mottram\n" +"# Date: 12/09/2002\n" +"#\n" +"# \n" +"# As defined in dna.c\n" +"#\n" +"#\n" + +"DESCRIPTION Navitrak DNA marker format\n" +"EXTENSION dna\n" + +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER COMMA\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS COMMA\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"IFIELD INDEX, \"\", \"%d\"\n" +"IFIELD LAT_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD LON_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD DESCRIPTION, \"\", \"%s\"\n" + +; +static char fugawi[] = +"# fugawi XCSV style file\n" +"#\n" +"# Format: Fugawi\n" +"# Author: Robert Lipe\n" +"# Date: 03/10/2003\n" +"#\n" +"# \n" + +"DESCRIPTION Fugawi\n" +"EXTENSION txt\n" +"SHORTLEN 10\n" + +"#\n" +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER COMMA\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS COMMA\n" + +"PROLOGUE \\# Latitude, Longitude and UTM coordinates are in WGS84 datum\n" +"PROLOGUE \\#\n" +"PROLOGUE \\# Every set of data contains the following:\n" +"PROLOGUE \\#\n" +"PROLOGUE \\# Waypoint name\n" +"PROLOGUE \\# Waypoint comment\n" +"PROLOGUE \\# Waypoint description\n" +"PROLOGUE \\# Latitude in Degree and decimals (soutern hemisphere has neg. degrees)\n" +"PROLOGUE \\# Longitude in degree and decimals (neg. numbers: west of Greenwich)\n" +"PROLOGUE \\# Height in meters\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"IFIELD SHORTNAME, \"\", \"%s\"\n" +"IFIELD DESCRIPTION, \"\", \"%s\"\n" +"IFIELD NOTES, \"\", \"%s\"\n" +"IFIELD LAT_DECIMAL, \"\", \"%-.7f\"\n" +"IFIELD LON_DECIMAL, \"\", \"%-.7f\"\n" +"IFIELD ALT_METERS, \"\", \"%-7.1f\"\n" +; +static char gpsdrive[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: GPSDrive\n" +"# Author: Alex Mottram\n" +"# Date: 12/11/2002\n" +"#\n" +"# \n" +"#\n" + +"DESCRIPTION GpsDrive Format\n" + +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER WHITESPACE\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS ,'\"\n" + +"SHORTLEN 20\n" +"SHORTWHITE 0\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" + +"IFIELD SHORTNAME, \"\", \"%s\"\n" +"IFIELD LAT_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD LON_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD ICON_DESCR, \"\", \"%s\"\n" + +"OFIELD ANYNAME, \"\", \"%s\"\n" +"OFIELD LAT_DECIMAL, \"\", \"%08.5f\"\n" +"OFIELD LON_DECIMAL, \"\", \"%08.5f\"\n" +"OFIELD ICON_DESCR, \"\", \"%s\"\n" +; +static char gpsman[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: GPSMAN Format\n" +"# Author: Alex Mottram\n" +"# Date: 12/09/2002\n" +"#\n" +"# \n" +"# As defined in gpsman.c\n" +"#\n" +"#\n" + +"DESCRIPTION GPSman\n" +"SHORTLEN 8\n" +"SHORTWHITE 0\n" + +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER TAB\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS TAB\n" + +"PROLOGUE !Format: DDD 1 WGS 84\n" +"PROLOGUE !W:\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"IFIELD SHORTNAME, \"\", \"%-8.8s\"\n" +"IFIELD DESCRIPTION, \"\", \"%s\"\n" +"IFIELD LAT_DIRDECIMAL, \"\", \"%c%f\"\n" +"IFIELD LON_DIRDECIMAL, \"\", \"%c%f\"\n" +"IFIELD IGNORE, \"\", \"%s\"\n" + +"# gpsman.c likes mkshort len = 8, whitespace = 0.\n" +; +static char mapconverter[] = +"# Format: Mapopolis.com Mapconverter\n" +"# Author: Gary Paulson\n" +"# Date: 01/13/2003\n" +"# Requires unsupported mapconverter.exe from mapopolis.com.\n" +"#\n" +"# Modifications by Alex Mottram documented 6/30/2003\n" +"# Change %-40.40s on description output to %-.40s to stop padding.\n" +"# Add QUOTE as badchars, remove COMMA.\n" +"# Removed Mapconverter.exe's README information from style file.\n" +"# Changed OFIELD to IFIELD in case you ever want to read one of these things.\n" +"#\n" +"#\n" +"DESCRIPTION Mapopolis.com Mapconverter CSV\n" +"EXTENSION txt\n" + +"# FILE LAYOUT DEFINITIIONS:\n" + +"FIELD_DELIMITER COMMASPACE\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS \",\n" + +"# Map Info Record (header):\n" +"PROLOGUE M, \"Geocaches\", \"GPSBabel\", Geocaches, __FILE__\n" +"#\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"# L Records:\n" +"IFIELD CONSTANT, \"L\", \"%s\" # [L]ANDMARK\n" +"IFIELD CONSTANT, \"Geocaches\", \"%s\" # Category for Landmark Searches\n" +"IFIELD DESCRIPTION, \"\", \"%-.40s\" # Name\n" +"IFIELD CONSTANT, \"1\", \"%s\" # View at Zoom Level 1 (1-4)\n" +"IFIELD LON_DECIMAL, \"\", \"%08.5f\" # Longitude\n" +"IFIELD LAT_DECIMAL, \"\", \"%08.5f\" # Latitude\n" +; +static char mxf[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: Ozi Explorer\n" +"# Author: Alex Mottram\n" +"# Date: 12/09/2002\n" +"#\n" +"# \n" +"# As used in mxf.c\n" +"#\n" +"#\n" + +"DESCRIPTION MapTech Exchange Format\n" +"EXTENSION mxf\n" + +"#\n" +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER COMMASPACE\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS \",\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"IFIELD LAT_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD LON_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD DESCRIPTION, \"\", \"%s\"\n" +"IFIELD SHORTNAME, \"\", \"%s\"\n" +"IFIELD IGNORE, \"\", \"%s\"\n" +"IFIELD CONSTANT, \"ff0000\", \"%s\" # COLOR\n" +"IFIELD CONSTANT, \"47\", \"%s\" # ICON\n" + +"OFIELD LAT_DECIMAL, \"\", \"%08.5f\"\n" +"OFIELD LON_DECIMAL, \"\", \"%08.5f\"\n" +"OFIELD DESCRIPTION, \"\", \"\"%s\"\"\n" +"OFIELD SHORTNAME, \"\", \"\"%s\"\"\n" +"OFIELD DESCRIPTION, \"\", \"\"%s\"\"\n" +"OFIELD CONSTANT, \"ff0000\", \"%s\" # COLOR\n" +"OFIELD CONSTANT, \"47\", \"%s\" # ICON\n" +; +static char nima[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: NIMA/GNIS Geographic Names File\n" +"# Author: Alex Mottram\n" +"# Date: 11/24/2002\n" +"#\n" + +"DESCRIPTION NIMA/GNIS Geographic Names File\n" + +"#\n" +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER TAB\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS TAB\n" +"PROLOGUE RC UFI UNI DD_LAT DD_LONG DMS_LAT DMS_LONG UTM JOG FC DSG PC CC1 ADM1 ADM2 DIM CC2 NT LC SHORT_FORM GENERIC SORT_NAME FULL_NAME FULL_NAME_ND MODIFY_DATE\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"IFIELD IGNORE, \"\", \"%s\" # RC\n" +"IFIELD IGNORE, \"\", \"%s\" # UFI\n" +"IFIELD IGNORE, \"\", \"%s\" # UNI\n" +"IFIELD LAT_DECIMAL, \"\", \"%f\" # DD_LAT\n" +"IFIELD LON_DECIMAL, \"\", \"%f\" # DD_LON\n" +"IFIELD IGNORE, \"\", \"%s\" # DMS_LAT\n" +"IFIELD IGNORE, \"\", \"%s\" # DMS_LON\n" +"IFIELD IGNORE, \"\", \"%s\" # UTM\n" +"IFIELD IGNORE, \"\", \"%s\" # JOG\n" +"IFIELD IGNORE, \"\", \"%s\" # FC\n" +"IFIELD IGNORE, \"\", \"%s\" # DSG\n" +"IFIELD IGNORE, \"\", \"%s\" # PC\n" +"IFIELD IGNORE, \"\", \"%s\" # CC1\n" +"IFIELD IGNORE, \"\", \"%s\" # ADM1\n" +"IFIELD IGNORE, \"\", \"%s\" # ADM2\n" +"IFIELD IGNORE, \"\", \"%s\" # DIM\n" +"IFIELD IGNORE, \"\", \"%s\" # CC2\n" +"IFIELD IGNORE, \"\", \"%s\" # NT\n" +"IFIELD IGNORE, \"\", \"%s\" # LC\n" +"IFIELD IGNORE, \"\", \"%s\" # SHORT_FORM\n" +"IFIELD IGNORE, \"\", \"%s\" # GENERIC\n" +"IFIELD SHORTNAME, \"\", \"%s\" # SORT_NAME \n" +"IFIELD IGNORE, \"\", \"%s\" # FULL_NAME (unicoded!)\n" +"IFIELD DESCRIPTION, \"\", \"%s\" # FULL_NAME_ND\n" +"IFIELD IGNORE, \"\", \"%s\" # MODIFY_DATE\n" +; +static char s_and_t[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: MS S&T 2002/2003\n" +"# Author: Alex Mottram\n" +"# Date: 12/09/2002\n" +"#\n" +"# \n" +"# As requested by Noel Shrum on the gpsbabel-code mailing list.\n" +"# Name,Latitude,Longitude,Name 2,URL,Type\n" +"# GCCBF,44.479133,-85.56515,High Rollaway by rjlint,http://www.geocaching.com/seek/cache_details.aspx?ID=3263,Traditional Cache\n" +"# GC110D,44.6522,-85.492483,Brown Bridge Pond Peek-a-Boo Cache by Big Bird,http://www.geocaching.com/seek/cache_details.aspx?ID=4365,Traditional Cache\n" +"# GC171C,44.70605,-85.62265,The Michigan Frog by RealDcoy & LRB,http://www.geocaching.com/seek/cache_details.aspx?ID=5916,Traditional Cache\n" +"#\n" + +"DESCRIPTION Microsoft Streets and Trips 2002/2003\n" + +"#\n" +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER COMMA\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS ,\"\n" + +"PROLOGUE Name,Latitude,Longitude,Name 2,URL,Type\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"# NOTE: MS S&T ONLY IMPORTS DATA, IT DOESN'T EXPORT THIS ANYWHERE SO WE CAN\n" +"# HAVE OUR WAY WITH THE FORMATTING. \n" +"#\n" +"IFIELD SHORTNAME, \"\", \"%s\" # Name\n" +"IFIELD LAT_DECIMAL, \"\", \"%f\" # Latitude\n" +"IFIELD LON_DECIMAL, \"\", \"%f\" # Longitude\n" +"IFIELD DESCRIPTION, \"\", \"%s\" # Name 2 (Big Description)\n" +"IFIELD URL, \"\", \"%s\" # URL\n" +"IFIELD IGNORE, \"\", \"\" # Holder for Geocache Type\n" +; +static char saplus[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: \n" +"# Author: Jim Bensman\n" +"# Date: 02/22/04\n" +"#\n" + +"DESCRIPTION Delorme Street Atlas Plus\n" + +"#\n" +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER COMMA\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS ,\"\n" + +"PROLOGUE Name 2,Name,Latitude,Longitude,URL,Type\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"IFIELD DESCRIPTION, \"\", \"%s\" # Name 2 (Big Description)\n" +"IFIELD SHORTNAME, \"\", \"%s\" # Name\n" +"IFIELD LAT_DECIMAL, \"\", \"%f\" # Latitude\n" +"IFIELD LON_DECIMAL, \"\", \"%f\" # Longitude\n" +"IFIELD URL, \"\", \"%s\" # URL\n" +"IFIELD IGNORE, \"\", \"\" # Holder for Geocache Type\n" + +; +static char tabsep[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: Dumps all fields in a traditional Unix tab separated style\n" +"#\n" +"# The order of the fields (with the exception of LAT_DIR/LON_DIR) was\n" +"# the same as documented in README.style when this format was created.\n" +"# LAT_DIR/LON_DIR were undocumented, so I stuck them at the end of the\n" +"# other lat/lon fields.\n" +"#\n" +"# However, please add any new gpsbabel fields to the end (to avoid\n" +"# upsetting existing applications) regardless of where they land in\n" +"# the README.style documentation.\n" +"#\n" + +"DESCRIPTION All database fields on one tab-separated line\n" + +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER TAB\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS TAB\n" +"FORMAT_TYPE INTERNAL\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS:\n" +"#\n" +"IFIELD INDEX, \"\", \"%d\"\n" +"IFIELD SHORTNAME, \"\", \"%s\"\n" +"IFIELD DESCRIPTION, \"\", \"%s\"\n" +"IFIELD NOTES, \"\", \"%s\"\n" +"IFIELD URL, \"\", \"%s\" \n" +"IFIELD URL_LINK_TEXT, \"\", \"%s\"\n" +"IFIELD ICON_DESCR, \"\", \"%s\"\n" +"IFIELD LAT_DECIMAL, \"\", \"%f\"\n" +"IFIELD LON_DECIMAL, \"\", \"%f\"\n" +"IFIELD LAT_INT32DEG, \"\", \"%ld\"\n" +"IFIELD LON_INT32DEG, \"\", \"%ld\"\n" +"IFIELD LAT_DECIMALDIR, \"\", \"%f%c\"\n" +"IFIELD LON_DECIMALDIR, \"\", \"%f%c\"\n" +"IFIELD LAT_DIRDECIMAL, \"\", \"%c%f\"\n" +"IFIELD LON_DIRDECIMAL, \"\", \"%c%f\"\n" +"IFIELD LAT_DIR, \"\", \"%c\"\n" +"IFIELD LON_DIR, \"\", \"%c\"\n" +"IFIELD ALT_FEET, \"\", \"%fF\"\n" +"IFIELD ALT_METERS, \"\", \"%fM\"\n" +"IFIELD EXCEL_TIME, \"\", \"%f\"\n" +"IFIELD TIMET_TIME, \"\", \"%ld\"\n" +"IFIELD GEOCACHE_DIFF,\"\",\"%3.1f\"\n" +"IFIELD GEOCACHE_TERR,\"\",\"%3.1f\"\n" +"IFIELD GEOCACHE_CONTAINER,\"\",\"%s\"\n" +"IFIELD GEOCACHE_TYPE,\"\",\"%s\"\n" +"IFIELD PATH_DISTANCE_MILES,\"\",\"%f\"\n" +"IFIELD PATH_DISTANCE_KM, \"\", \"%f\"\n" +; +static char xmap[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: Delorme Xmap Conduit\n" +"# Author: Alex Mottram\n" +"# Date: 12/09/2002\n" +"#\n" +"# \n" +"# As defined in csv.c/xmap\n" +"#\n" + +"DESCRIPTION Delorme XMap HH Native .WPT\n" +"EXTENSION wpt\n" + +"#\n" +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER COMMASPACE\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS COMMA\n" + +"PROLOGUE BEGIN SYMBOL\n" +"EPILOGUE END\n" +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"IFIELD LAT_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD LON_DECIMAL, \"\", \"%08.5f\"\n" +"IFIELD DESCRIPTION, \"\", \"%s\"\n" +; +static char xmapwpt[] = +"# gpsbabel XCSV style file\n" +"#\n" +"# Format: Delorme Xmap HH Street Atlas USA .WPT (PocketPC)\n" +"# Author: Alex Mottram\n" +"# Date: 12/09/2002\n" +"#\n" +"# \n" +"DESCRIPTION Delorme XMat HH Street Atlas USA .WPT (PPC)\n" +"SHORTLEN 32\n" +"SHORTWHITE 0\n" + +"#\n" +"#\n" +"# FILE LAYOUT DEFINITIIONS:\n" +"#\n" +"FIELD_DELIMITER COLON\n" +"RECORD_DELIMITER NEWLINE\n" +"BADCHARS COLON\n" + +"#\n" +"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" +"#\n" +"IFIELD CONSTANT, \"1296126539\", \"%s\"\n" +"IFIELD CONSTANT, \"1481466224\", \"%s\"\n" +"IFIELD LAT_INT32DEG, \"\", \"%d\"\n" +"IFIELD LON_INT32DEG, \"\", \"%d\"\n" +"IFIELD CONSTANT, \"3137157\", \"%s\"\n" +"IFIELD SHORTNAME, \"\", \"%-.31s\"\n" +"IFIELD IGNORE, \"\", \"%-.31s\"\n" +"IFIELD DESCRIPTION, \"\", \"%-.78s\"\n" +; +#include "defs.h" +style_vecs_t style_list[] = {{ "xmapwpt", xmapwpt } , { "xmap", xmap } , { "tabsep", tabsep } , { "saplus", saplus } , { "s_and_t", s_and_t } , { "nima", nima } , { "mxf", mxf } , { "mapconverter", mapconverter } , { "gpsman", gpsman } , { "gpsdrive", gpsdrive } , { "fugawi", fugawi } , { "dna", dna } , { "custom", custom } , { "csv", csv } , { "arc", arc } , {0,0}}; +size_t nstyles = 15; diff --git a/jeeps/README b/jeeps/README new file mode 100644 index 000000000..f626fc4c5 --- /dev/null +++ b/jeeps/README @@ -0,0 +1 @@ +This is from jeeps-0.1.3. This code is under GPL. diff --git a/jeeps/garminusb.h b/jeeps/garminusb.h new file mode 100644 index 000000000..edc7b800d --- /dev/null +++ b/jeeps/garminusb.h @@ -0,0 +1,58 @@ +/* + Definitions for Garmin USB protocol and implementation. + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include + +/* This structure is a bit funny looking to avoid variable length + * arrays which aren't present in C89. This contains the visible + * fields in the USB packets of the Garmin USB receivers (60C, 76C, etc.) + * All data are little endian. + */ +typedef +union { + struct { + unsigned char type; + unsigned char reserved1; + unsigned char reserved2; + unsigned char reserved3; + unsigned char pkt_id[2]; + unsigned char reserved6; + unsigned char reserved7; + unsigned char datasz[4]; + unsigned char databuf[1]; /* actually an variable length array... */ + } gusb_pkt; + unsigned char dbuf[1024]; +} garmin_usb_packet; + +/* + * Internal interfaces that are common regardless of underlying + * OS implementation. + */ +#define GUSB_MAX_UNITS 20 +struct { + unsigned long serial_number; + char *os_identifier; /* In case the OS has another name for it. */ + char *product_identifier; /* From the hardware itself. */ +} garmin_unit_info[GUSB_MAX_UNITS]; + +int gusb_cmd_send(const garmin_usb_packet *obuf, size_t sz); +int gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz); +int gusb_open(const char *portname); +int gusb_close(const char *portname); diff --git a/jeeps/gps.h b/jeeps/gps.h new file mode 100644 index 000000000..2c6f0c196 --- /dev/null +++ b/jeeps/gps.h @@ -0,0 +1,198 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gps_h +#define gps_h + +#include "../defs.h" +#include "gpsport.h" +#include + +#define FRAMING_ERROR -1 +#define PROTOCOL_ERROR -2 +#define HARDWARE_ERROR -3 +#define SERIAL_ERROR -4 +#define MEMORY_ERROR -5 +#define GPS_UNSUPPORTED -6 +#define INPUT_ERROR -7 + +#define MAX_GPS_PACKET_SIZE 1024 +#define GPS_TIME_OUT 5 + +#define gpsTrue 1 +#define gpsFalse 0 + +#define DLE 0x10 +#define ETX 0x03 + + +extern int32 gps_errno; +extern int32 gps_warning; +extern int32 gps_error; +extern int32 gps_user; +extern int32 gps_show_bytes; + + +typedef struct GPS_SPacket +{ + UC dle; + UC type; + UC n; + UC *data; + UC chk; + UC edle; + UC etx; + UC bytes; /* Actual number of bytes (for sending) */ +} GPS_OPacket, *GPS_PPacket; + + + +typedef struct GPS_SProduct_Data_Type +{ + int16 id; + int16 version; + char desc[MAX_GPS_PACKET_SIZE]; +} GPS_OProduct_Data_Type, *GPS_PProduct_Data_Type; + + + + +typedef struct GPS_SPvt_Data_Type +{ + float alt; + float epe; + float eph; + float epv; + int16 fix; + double tow; + double lat; + double lon; + float east; + float north; + float up; + float msl_hght; + int16 leap_scnds; + int32 wn_days; +} GPS_OPvt_Data, *GPS_PPvt_Data; + + + +typedef struct GPS_STrack +{ + double lat; /* Degrees */ + double lon; /* Degrees */ + time_t Time; /* Unix time */ + float alt; /* Altitude */ + float dpth; /* Depth */ + int32 tnew; /* New track? */ + int32 ishdr; /* Track header? */ + int32 dspl; /* Display on map? */ + int32 colour; /* Colour */ + char trk_ident[256]; /* Track identifier */ +} +GPS_OTrack, *GPS_PTrack; + + + +typedef struct GPS_SAlmanac +{ + UC svid; + int16 wn; + float toa; + float af0; + float af1; + float e; + float sqrta; + float m0; + float w; + float omg0; + float odot; + float i; + UC hlth; +} GPS_OAlmanac, *GPS_PAlmanac; + + +typedef struct GPS_SWay +{ + char ident[256]; + double lat; + double lon; + char cmnt[256]; + float dst; + int32 smbl; + int32 dspl; + char wpt_ident[256]; + char lnk_ident[256]; + UC subclass[18]; + int32 colour; + char cc[2]; + UC wpt_class; + float alt; + char city[24]; + char state[2]; + char name[30]; + char facility[32]; + char addr[52]; + char cross_road[52]; + int32 attr; + float dpth; + int32 idx; + int32 prot; + int32 isrte; + int32 rte_prot; + UC rte_num; + char rte_cmnt[20]; + char rte_ident[256]; + int32 islink; + int32 rte_link_class; + char rte_link_subclass[18]; + char rte_link_ident[256]; +} GPS_OWay, *GPS_PWay; + + + + +#include "gpsserial.h" +#include "gpssend.h" +#include "gpsread.h" +#include "gpsutil.h" +#include "gpsapp.h" +#include "gpsprot.h" +#include "gpscom.h" +#include "gpsfmt.h" +#include "gpsmath.h" +#include "gpsnmea.h" +#include "gpsmem.h" +#include "gpsrqst.h" +#include "gpsinput.h" +#include "gpsproj.h" +#include "gpsnmeafmt.h" +#include "gpsnmeaget.h" + +time_t gps_save_time; +double gps_save_lat; +double gps_save_lon; +extern int32 gps_save_id; +extern double gps_save_version; +extern char gps_save_string[GPS_ARB_LEN]; +extern int gps_is_usb; + + +extern struct COMMANDDATA COMMAND_ID[2]; +extern struct LINKDATA LINK_ID[3]; +extern struct GPS_MODEL_PROTOCOL GPS_MP[]; + +extern char *gps_marine_sym[]; +extern char *gps_land_sym[]; +extern char *gps_aviation_sym[]; +extern char *gps_16_sym[]; + + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsapp.c b/jeeps/gpsapp.c new file mode 100644 index 000000000..2db5a4df8 --- /dev/null +++ b/jeeps/gpsapp.c @@ -0,0 +1,5757 @@ +/******************************************************************** +** @source JEEPS application and data functions +** +** @author Copyright (C) 1999 Alan Bleasby +** @version 1.0 +** @modified Dec 28 1999 Alan Bleasby. First version +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include +#include +#include +#include + +#define XMIN(a,b) (a < b? a : b) + +static int32 GPS_A000(const char *port); +static void GPS_A001(GPS_PPacket packet); + + +static void GPS_A500_Translate(UC *s, GPS_PAlmanac *alm); +static void GPS_A500_Encode(UC *s, GPS_PAlmanac alm); +static void GPS_A300_Translate(UC *s, GPS_PTrack *trk); +static void GPS_A300_Encode(UC *s, GPS_PTrack trk); + + +static void GPS_D100_Get(GPS_PWay *way, UC *s); +static void GPS_D101_Get(GPS_PWay *way, UC *s); +static void GPS_D102_Get(GPS_PWay *way, UC *s); +static void GPS_D103_Get(GPS_PWay *way, UC *s); +static void GPS_D104_Get(GPS_PWay *way, UC *s); +static void GPS_D105_Get(GPS_PWay *way, UC *s); +static void GPS_D106_Get(GPS_PWay *way, UC *s); +static void GPS_D107_Get(GPS_PWay *way, UC *s); +static void GPS_D108_Get(GPS_PWay *way, UC *s); +static void GPS_D109_Get(GPS_PWay *way, UC *s); +static void GPS_D150_Get(GPS_PWay *way, UC *s); +static void GPS_D151_Get(GPS_PWay *way, UC *s); +static void GPS_D152_Get(GPS_PWay *way, UC *s); +static void GPS_D154_Get(GPS_PWay *way, UC *s); +static void GPS_D155_Get(GPS_PWay *way, UC *s); + +static void GPS_D100_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D101_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D102_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D103_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D104_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D105_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D106_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D107_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D108_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D109_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D150_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D151_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D152_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D154_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D155_Send(UC *data, GPS_PWay way, int32 *len); + +static void GPS_D200_Get(GPS_PWay *way, UC *s); +static void GPS_D201_Get(GPS_PWay *way, UC *s); +static void GPS_D202_Get(GPS_PWay *way, UC *s); +static void GPS_D210_Get(GPS_PWay *way, UC *s); +static void GPS_D200_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D201_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D202_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D210_Send(UC *data, GPS_PWay way, int32 *len); + +static void GPS_D400_Get(GPS_PWay *way, UC *s); +static void GPS_D403_Get(GPS_PWay *way, UC *s); +static void GPS_D450_Get(GPS_PWay *way, UC *s); +static void GPS_D400_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D403_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D450_Send(UC *data, GPS_PWay way, int32 *len); + +static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, int32 fd); +static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, int32 fd); +static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, int32 fd); +static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, int32 fd); +static void GPS_D500_Send(UC *data, GPS_PAlmanac alm); +static void GPS_D501_Send(UC *data, GPS_PAlmanac alm); +static void GPS_D550_Send(UC *data, GPS_PAlmanac alm); +static void GPS_D551_Send(UC *data, GPS_PAlmanac alm); + + +int32 gps_save_id; +int gps_is_usb; +double gps_save_version; +char gps_save_string[GPS_ARB_LEN]; + + +/* @func GPS_Init ****************************************************** +** +** Initialise GPS communication +** Get capabilities and store time lat/lon in case GPS requests +** it later. +** Find endian nature of hardware and store +** +** @param [r] port [const char *] serial port +** +** @return [int32] 1 if success -ve if error +************************************************************************/ +int32 GPS_Init(const char *port) +{ + int32 ret; + + (void) GPS_Util_Little(); + + /* + * Decide here if the portname refers to a USB device and set the + * global that's used as in inflection point for other decisions later. + */ + gps_is_usb = (0 == strncmp(port, "usb:", 4)); + + ret = GPS_A000(port); + if(ret<0) return ret; + if (gps_is_usb) return 1; + gps_save_time = GPS_Command_Get_Time(port); + if(!gps_save_time) { + return FRAMING_ERROR; + } + + if (0 == strncmp(gps_save_string, "GPilotS", 7)) { + return 1; + } + + return GPS_Command_Get_Position(port,&gps_save_lat,&gps_save_lon); +} + + +/* @funcstatic GPS_A000 ************************************************ +** +** Return product ID, version and description. Turn off PVT transfer +** +** @param [r] port [const char *] serial port +** +** @return [int32] 1 if success -ve if error +************************************************************************/ +static int32 GPS_A000(const char *port) +{ + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int16 version; + int16 id; + char tstr[256]; + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!gps_is_usb && !GPS_Serial_Flush(fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Make_Packet(&tra, LINK_ID[0].Pid_Product_Rqst,NULL,0); + if(!GPS_Write_Packet(fd,tra)) + return SERIAL_ERROR; + + if(!GPS_Get_Ack(fd, &tra, &rec)) + return SERIAL_ERROR; + + GPS_Packet_Read(fd, &rec); + GPS_Send_Ack(fd, &tra, &rec); + + id = GPS_Util_Get_Short(rec->data); + version = GPS_Util_Get_Short((rec->data)+2); + + (void) strcpy(gps_save_string,(char *)rec->data+4); + GPS_User((char *)rec->data+4); + (void) sprintf(tstr,"ID:\t\t%d\n",id); + gps_save_id = id; + GPS_User(tstr); + gps_save_version = (double)((double)version/(double)100.); + (void) sprintf(tstr, + "Version:\t%.2f\n",gps_save_version); + GPS_User(tstr); + + + gps_date_time_transfer = pA600; + gps_date_time_type = pD600; /* All models so far */ + gps_position_transfer = pA700; + gps_position_type = pD700; /* All models so far */ + gps_pvt_transfer = -1; + gps_pvt_type = -1; + gps_prx_waypt_transfer = -1; + gps_prx_waypt_type = -1; + gps_trk_transfer = -1; + gps_trk_type = -1; + gps_trk_hdr_type = -1; + gps_rte_link_type = -1; + + if(!GPS_Serial_Wait(fd)) + { + GPS_Warning("A001 protocol not supported"); + id = GPS_Protocol_Version_Change(id,version); + if(GPS_Protocol_Table_Set(id)<0) + return GPS_UNSUPPORTED; + } + else + { + int maxct = 3; + /* + * The unit may return more than one packet, so read and + * discard all but the product inquiry response. + */ + while (maxct--) { + (void) GPS_Packet_Read(fd, &rec); + GPS_Send_Ack(fd, &tra, &rec); + if (rec->type == 0xfd) { + GPS_A001(rec); + break; + } + } + } + + /* Make sure PVT is off as some GPS' have it on by default */ + if(gps_pvt_transfer != -1) + GPS_A800_Off(port,&fd); + + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return 1; +} + + + + +/* @funcstatic GPS_A001 ************************************************ +** +** Extract protocol capabilities +** This routine could do with re-writing. It's too long and obtuse. +** +** @param [r] packet [GPS_PPacket] A001 protocol packet +** +** @return [void] +************************************************************************/ +static void GPS_A001(GPS_PPacket packet) +{ + int32 entries; + int32 i; + UC *p; + US tag; + US data; + US lasta=0; + + gps_link_type = -1; + gps_device_command = -1; + gps_waypt_transfer = -1; + gps_waypt_type = -1; + gps_route_transfer = -1; + gps_rte_hdr_type = -1; + gps_rte_type = -1; + gps_trk_transfer = -1; + gps_trk_type = -1; + gps_prx_waypt_transfer = -1; + gps_prx_waypt_type = -1; + gps_almanac_transfer = -1; + gps_almanac_type = -1; + + entries = packet->n / 3; + p = packet->data; + + for(i=0;i=100) + { + gps_waypt_type = data; + continue; + } + if(data<153 && data>=150) + { + gps_waypt_type = data; + continue; + } + if(data<156 && data>=154) + { + gps_waypt_type = data; + continue; + } + else + GPS_Protocol_Error(tag,data); + } + + + else if(lasta<300) + { + if(data>=200 && data <=202) + { + gps_rte_hdr_type = data; + continue; + } + if(data==210) + { + gps_rte_link_type = data; + continue; + } + + if(data<=109 && data>=100) + { + gps_rte_type = data; + continue; + } + if(data<153 && data>=150) + { + gps_rte_type = data; + continue; + } + if(data<156 && data>=154) + { + gps_rte_type = data; + continue; + } + if(data<451) + { + if(data==400) + gps_rte_type = pD400; + else if(data==403) + gps_rte_type = pD403; + else if(data==450) + gps_rte_type = pD450; + else + GPS_Protocol_Error(tag,data); + continue; + } + } + + else if(lasta<400) + { + switch (data) { + case 300: gps_trk_type = pD300; break; + case 301: gps_trk_type = pD301; break; + case 302: gps_trk_type = pD302; break; + case 310: gps_trk_hdr_type = pD310; break; + case 311: gps_trk_hdr_type = pD311; break; + case 312: gps_trk_hdr_type = pD312; break; + default: GPS_Protocol_Error(tag,data); break; + } + continue; + } + + + else if(lasta<500) + { + if(data<=109 && data>=100) + { + gps_prx_waypt_type = data; + continue; + } + if(data<153 && data>=150) + { + gps_prx_waypt_type = data; + continue; + } + if(data<156 && data>=154) + { + gps_prx_waypt_type = data; + continue; + } + if(data<451) + { + if(data==400) + gps_prx_waypt_type = pD400; + else if(data==403) + gps_prx_waypt_type = pD403; + else if(data==450) + gps_prx_waypt_type = pD450; + else + GPS_Protocol_Error(tag,data); + continue; + } + } + + else if(lasta<600) + { + if(data==500) + gps_almanac_type = pD500; + else if(data==501) + gps_almanac_type = pD501; + else if(data==550) + gps_almanac_type = pD550; + else if(data==551) + gps_almanac_type = pD551; + else + GPS_Protocol_Error(tag,data); + continue; + } + + else if(lasta<700) + { + if (data == 600) { + gps_date_time_type = pD600; + } else { + /* Stupid undocumented 60 D601 packets */ + /* GPS_Protocol_Error(tag,data); */ + continue; + } + continue; + } + else if(lasta<800) + { + if(data!=700) + GPS_Protocol_Error(tag,data); + else + gps_position_type = pD700; + continue; + } + else if(lasta<900) + { + if (data == 800) + gps_pvt_type = pD800; + /* + * Stupid, undocumented Vista 3.60 D802 packets + else + GPS_Protocol_Error(tag,data); + */ + continue; + } + + + } + } + + return; +} + + + + +/* @func GPS_A100_Get ****************************************************** +** +** Get waypoint data from GPS +** +** @param [r] port [const char *] serial port +** @param [w] way [GPS_PWay **] waypoint array +** +** @return [int32] number of waypoint entries +************************************************************************/ +int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)()) +{ + static UC data[2]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 n; + int32 i; + + + if(!GPS_Serial_On(port,&fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Transfer_Wpt); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + + if(!GPS_Write_Packet(fd,tra)) + { + GPS_Error("A100_Get: Cannot write packet"); + return FRAMING_ERROR; + } + + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A100_Get: No acknowledge"); + return FRAMING_ERROR; + } + + GPS_Packet_Read(fd, &rec); + GPS_Send_Ack(fd, &tra, &rec); + + n = GPS_Util_Get_Short(rec->data); + + if(n) + if(!((*way)=(GPS_PWay *)malloc(n*sizeof(GPS_PWay)))) + { + GPS_Error("A100_Get: Insufficient memory"); + return MEMORY_ERROR; + } + + for(i=0;idata); + break; + case pD101: + GPS_D101_Get(&((*way)[i]),rec->data); + break; + case pD102: + GPS_D102_Get(&((*way)[i]),rec->data); + break; + case pD103: + GPS_D103_Get(&((*way)[i]),rec->data); + break; + case pD104: + GPS_D104_Get(&((*way)[i]),rec->data); + break; + case pD105: + GPS_D105_Get(&((*way)[i]),rec->data); + break; + case pD106: + GPS_D106_Get(&((*way)[i]),rec->data); + break; + case pD107: + GPS_D107_Get(&((*way)[i]),rec->data); + break; + case pD108: + GPS_D108_Get(&((*way)[i]),rec->data); + break; + case pD109: + GPS_D109_Get(&((*way)[i]),rec->data); + break; + case pD150: + GPS_D150_Get(&((*way)[i]),rec->data); + break; + case pD151: + GPS_D151_Get(&((*way)[i]),rec->data); + break; + case pD152: + GPS_D152_Get(&((*way)[i]),rec->data); + break; + case pD154: + GPS_D154_Get(&((*way)[i]),rec->data); + break; + case pD155: + GPS_D155_Get(&((*way)[i]),rec->data); + break; + default: + GPS_Error("A100_GET: Unknown waypoint protocol"); + return PROTOCOL_ERROR; + } + /* Issue callback for status updates. */ + if (cb) { + cb(n, &((*way)[i])); + } + } + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("A100_GET: Error transferring waypoints"); + return FRAMING_ERROR; + } + + if(i != n) + { + GPS_Error("A100_GET: Waypoint entry number mismatch"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return n; +} + + + + + +/* @func GPS_A100_Send ************************************************** +** +** Send waypoints to GPS +** +** @param [r] port [const char *] serial port +** @param [r] trk [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** +** @return [int32] success +************************************************************************/ +int32 GPS_A100_Send(const char *port, GPS_PWay *way, int32 n, int (*cb)()) +{ + UC data[GPS_ARB_LEN]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 i; + int32 len; + + if(!GPS_Serial_On(port,&fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Util_Put_Short(data,n); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Records, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("Waypoint start data not acknowledged"); + return gps_errno; + } + + + for(i=0;iprot = 100; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + return; +} + + + +/* @funcstatic GPS_D101_Get ********************************************* +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D101_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 101; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->dst = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*way)->smbl = *p; + + return; +} + + + +/* @funcstatic GPS_D102_Get ******************************************** +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D102_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 102; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->dst = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*way)->smbl = GPS_Util_Get_Short(p); + + + return; +} + + + +/* @funcstatic GPS_D103_Get ********************************************* +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D103_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 103; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->smbl = *p++; + (*way)->dspl = *p; + + + return; +} + + + +/* @funcstatic GPS_D104_Get ******************************************** +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D104_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 104; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->dst = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*way)->smbl = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + (*way)->dspl = *p; + + return; +} + + + +/* @funcstatic GPS_D105_Get ******************************************** +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D105_Get(GPS_PWay *way, UC *s) +{ + UC *p; + UC *q; + + p=s; + + (*way)->prot = 105; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->smbl = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + q = (UC *) (*way)->wpt_ident; + while((*q++ = *p++)); + + return; +} + + + +/* @funcstatic GPS_D106_Get ******************************************** +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +void GPS_D106_Get(GPS_PWay *way, UC *s) +{ + UC *p; + UC *q; + int32 i; + + p=s; + + (*way)->prot = 106; + + (*way)->wpt_class = *p++; + + for(i=0;i<13;++i) (*way)->subclass[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->smbl = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + q = (UC *) (*way)->wpt_ident; + while((*q++ = *p++)); + q = (UC *) (*way)->lnk_ident; + while((*q++ = *p++)); + + return; +} + + + +/* @funcstatic GPS_D107_Get ******************************************** +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D107_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 107; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->smbl = *p++; + (*way)->dspl = *p++; + + (*way)->dst = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*way)->colour = *p++; + + return; +} + + + +/* @funcstatic GPS_D108_Get ******************************************** +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D108_Get(GPS_PWay *way, UC *s) +{ + UC *p; + UC *q; + + int32 i; + + p=s; + + (*way)->prot = 108; + + (*way)->wpt_class = *p++; + (*way)->colour = *p++; + (*way)->dspl = *p++; + (*way)->attr = *p++; + (*way)->smbl = GPS_Util_Get_Short(p); + p+=sizeof(int16); + for(i=0;i<18;++i) (*way)->subclass[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->alt = GPS_Util_Get_Float(p); + p+=sizeof(float); + (*way)->dpth = (int32)GPS_Util_Get_Float(p); + p+=sizeof(float); + (*way)->dst = (int32)GPS_Util_Get_Float(p); + p+=sizeof(float); + + for(i=0;i<2;++i) (*way)->state[i] = *p++; + for(i=0;i<2;++i) (*way)->cc[i] = *p++; + + q = (UC *) (*way)->ident; + while((*q++ = *p++)); + + q = (UC *) (*way)->cmnt; + while((*q++ = *p++)); + + q = (UC *) (*way)->facility; + while((*q++ = *p++)); + + q = (UC *) (*way)->city; + while((*q++ = *p++)); + + q = (UC *) (*way)->addr; + while((*q++ = *p++)); + + q = (UC *) (*way)->cross_road; + while((*q++ = *p++)); + + return; +} + +/* @funcstatic GPS_D109_Get ******************************************** +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D109_Get(GPS_PWay *way, UC *s) +{ + UC *p; + UC *q; + + int32 i; + + p=s; + + (*way)->prot = 109; + (*way)->wpt_class = *p++; + (*way)->colour = *p++; + (*way)->dspl = *p++; + (*way)->attr = *p++; + (*way)->smbl = GPS_Util_Get_Short(p); + p+=sizeof(int16); + for(i=0;i<18;++i) (*way)->subclass[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->alt = GPS_Util_Get_Float(p); + p+=sizeof(float); + (*way)->dpth = (int32)GPS_Util_Get_Float(p); + p+=sizeof(float); + (*way)->dst = (int32)GPS_Util_Get_Float(p); + p+=sizeof(float); + + for(i=0;i<2;++i) (*way)->state[i] = *p++; + for(i=0;i<2;++i) (*way)->cc[i] = *p++; + + p += 4; /* Skip over "outbound link ete in seconds */ + + q = (UC *) (*way)->ident; + while((*q++ = *p++)); + + q = (UC *) (*way)->cmnt; + while((*q++ = *p++)); + + q = (UC *) (*way)->facility; + while((*q++ = *p++)); + + q = (UC *) (*way)->city; + while((*q++ = *p++)); + + q = (UC *) (*way)->addr; + while((*q++ = *p++)); + + q = (UC *) (*way)->cross_road; + while((*q++ = *p++)); + + return; +} + + +/* @funcstatic GPS_D150_Get ******************************************** +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D150_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 150; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + for(i=0;i<2;++i) (*way)->cc[i] = *p++; + (*way)->wpt_class = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->alt = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + for(i=0;i<24;++i) (*way)->city[i] = *p++; + for(i=0;i<2;++i) (*way)->state[i] = *p++; + for(i=0;i<30;++i) (*way)->name[i] = *p++; + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + return; +} + + + +/* @funcstatic GPS_D151_Get ********************************************* +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D151_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 151; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->dst = GPS_Util_Get_Float(p); + p+=sizeof(float); + + for(i=0;i<30;++i) (*way)->name[i] = *p++; + for(i=0;i<24;++i) (*way)->city[i] = *p++; + for(i=0;i<2;++i) (*way)->state[i] = *p++; + + (*way)->alt = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + for(i=0;i<2;++i) (*way)->cc[i] = *p++; + + ++p; + + (*way)->wpt_class = *p; + + return; +} + + + +/* @funcstatic GPS_D152_Get ******************************************** +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D152_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 152; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->dst = GPS_Util_Get_Float(p); + p+=sizeof(float); + + for(i=0;i<30;++i) (*way)->name[i] = *p++; + for(i=0;i<24;++i) (*way)->city[i] = *p++; + for(i=0;i<2;++i) (*way)->state[i] = *p++; + + (*way)->alt = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + for(i=0;i<2;++i) (*way)->cc[i] = *p++; + + ++p; + + (*way)->wpt_class = *p; + + return; +} + + +/* @funcstatic GPS_D154_Get ******************************************** +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D154_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 154; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->dst = GPS_Util_Get_Float(p); + p+=sizeof(float); + + for(i=0;i<30;++i) (*way)->name[i] = *p++; + for(i=0;i<24;++i) (*way)->city[i] = *p++; + for(i=0;i<2;++i) (*way)->state[i] = *p++; + + (*way)->alt = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + for(i=0;i<2;++i) (*way)->cc[i] = *p++; + + ++p; + + (*way)->wpt_class = *p++; + + (*way)->smbl = GPS_Util_Get_Short(p); + + return; +} + + +/* @funcstatic GPS_D155_Get ********************************************* +** +** Get waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D155_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 155; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->dst = GPS_Util_Get_Float(p); + p+=sizeof(float); + + for(i=0;i<30;++i) (*way)->name[i] = *p++; + for(i=0;i<24;++i) (*way)->city[i] = *p++; + for(i=0;i<2;++i) (*way)->state[i] = *p++; + + (*way)->alt = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + for(i=0;i<2;++i) (*way)->cc[i] = *p++; + + ++p; + + (*way)->wpt_class = *p++; + + (*way)->smbl = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + (*way)->dspl = *p; + + return; +} + + + +/* @funcstatic GPS_D100_Send ******************************************* +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D100_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + + *len = 58; + + return; +} + + +/* @funcstatic GPS_D101_Send ******************************************** +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D101_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + + GPS_Util_Put_Float(p,way->dst); + p+= sizeof(float); + + *p = way->smbl; + + *len = 63; + + return; +} + + +/* @funcstatic GPS_D102_Send ******************************************** +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D102_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + + GPS_Util_Put_Float(p,way->dst); + p+= sizeof(float); + + GPS_Util_Put_Short(p,way->smbl); + + *len = 64; + + return; +} + + +/* @funcstatic GPS_D103_Send ******************************************* +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D103_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) { + if (way->ident[i] == 0) { + memset(p, ' ', 6-i); + p+=6-i; + break; + } + *p++ = way->ident[i]; + } + + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + + *p++ = way->smbl; + *p = way->dspl; + + *len = 60; + + return; +} + + +/* @funcstatic GPS_D104_Send ******************************************** +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D104_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + /* byonke confirms that sending lower case comment data to a III+ + * results in the comment being truncated there. So we uppercase + * the entire comment. + */ + for(i=0;i<40;++i) *p++ = toupper(way->cmnt[i]); + + GPS_Util_Put_Float(p,way->dst); + p+= sizeof(float); + + GPS_Util_Put_Short(p,way->smbl); + p+=sizeof(int16); + + *p = 3; /* display symbol with waypoint name */ + + *len = 65; + + return; +} + + +/* @funcstatic GPS_D105_Send ******************************************* +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D105_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + UC *q; + + p = data; + + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + + GPS_Util_Put_Short(p,way->smbl); + p+=sizeof(int16); + + q = (UC *) way->wpt_ident; + while((*p++ = *q++)); + + + *len = p-data; + + return; +} + + +/* @funcstatic GPS_D106_Send ******************************************** +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D106_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + UC *q; + int32 i; + + p = data; + + *p++ = way->wpt_class; + for(i=0;i<13;++i) *p++ = way->subclass[i]; + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + + GPS_Util_Put_Short(p,way->smbl); + p+=sizeof(int16); + + q = (UC *) way->wpt_ident; + while((*p++ = *q++)); + q = (UC *) way->lnk_ident; + while((*p++ = *q++)); + + *len = p-data; + + return; +} + + +/* @funcstatic GPS_D107_Send ******************************************** +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D107_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + for(i=0;i<6;++i) *p++ = way->ident[i]; + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + + *p++ = way->smbl; + *p++ = way->dspl; + + GPS_Util_Put_Float(p,way->dst); + p+= sizeof(float); + + *p = way->colour; + + *len = 65; + + return; +} + + + +/* @funcstatic GPS_D108_Send ******************************************** +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D108_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + UC *q; + + int32 i; + + p = data; + + *p++ = way->wpt_class; + *p++ = way->colour; + *p++ = way->dspl; + *p++ = 0x60; + GPS_Util_Put_Short(p,way->smbl); + p+=sizeof(int16); + for(i=0;i<18;++i) *p++ = way->subclass[i]; + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + + GPS_Util_Put_Float(p,way->alt); + p+=sizeof(float); + GPS_Util_Put_Float(p,way->dpth); + p+=sizeof(float); + GPS_Util_Put_Float(p,way->dst); + p+=sizeof(float); + + for(i=0;i<2;++i) *p++ = way->state[i]; + for(i=0;i<2;++i) *p++ = way->cc[i]; + + + q = (UC *) way->ident; + i = XMIN(51, sizeof(way->ident)); + while((*p++ = *q++) && i--); + q = (UC *) way->cmnt; + i = XMIN(51, sizeof(way->cmnt)); + while((*p++ = *q++) && i--); + q = (UC *) way->facility; + i = XMIN(31, sizeof(way->facility)); + while((*p++ = *q++) && i--); + q = (UC *) way->city; + i = XMIN(25, sizeof(way->city)); + while((*p++ = *q++) && i--); + q = (UC *) way->addr; + i = XMIN(51, sizeof(way->addr)); + while((*p++ = *q++) && i--); + q = (UC *) way->cross_road; + i = XMIN(51, sizeof(way->cross_road)); + while((*p++ = *q++) && i--); + + *len = p-data; + + return; +} + + +/* @funcstatic GPS_D109_Send ******************************************** +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D109_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + UC *q; + + int32 i; + + p = data; + *p++ = 1 /* way->wpt_class */; /* For D109, the class must be 1 */ + *p++ = 0 /* way->colour*/ ; /* If non-zero, the waypoint is in + invisible ink on the V. */ + *p++ = way->dspl; + *p++ = 0x70; + GPS_Util_Put_Short(p,way->smbl); + p+=sizeof(int16); + for(i=0;i<18;++i) *p++ = way->subclass[i]; + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Float(p,way->alt); + p+=sizeof(float); + GPS_Util_Put_Float(p,way->dpth); + p+=sizeof(float); + GPS_Util_Put_Float(p,way->dst); + p+=sizeof(float); + + for(i=0;i<2;++i) *p++ = way->state[i]; + for(i=0;i<2;++i) *p++ = way->cc[i]; + for(i=0;i<4;++i) *p++ = 0xff; /* D109 silliness for ETE */ + + q = (UC *) way->ident; + i = XMIN(51, sizeof(way->ident)); + while((*p++ = *q++) && i--); + q = (UC *) way->cmnt; + i = XMIN(51, sizeof(way->cmnt)); + while((*p++ = *q++) && i--); + q = (UC *) way->facility; + i = XMIN(31, sizeof(way->facility)); + while((*p++ = *q++) && i--); + q = (UC *) way->city; + i = XMIN(25, sizeof(way->city)); + while((*p++ = *q++) && i--); + q = (UC *) way->addr; + i = XMIN(51, sizeof(way->addr)); + while((*p++ = *q++) && i--); + q = (UC *) way->cross_road; + i = XMIN(51, sizeof(way->cross_road)); + while((*p++ = *q++) && i--); + *len = p-data; + return; +} + + +/* @funcstatic GPS_D150_Send ******************************************** +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D150_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + for(i=0;i<2;++i) *p++ = way->cc[i]; + + if(way->wpt_class == 7) way->wpt_class = 0; + *p++ = way->wpt_class; + + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + + GPS_Util_Put_Short(p,way->alt); + p+=sizeof(int16); + + for(i=0;i<24;++i) *p++ = way->city[i]; + for(i=0;i<2;++i) *p++ = way->state[i]; + for(i=0;i<30;++i) *p++ = way->name[i]; + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + + *len = 115; + + return; +} + + +/* @funcstatic GPS_D151_Send ******************************************** +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D151_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + GPS_Util_Put_Float(p,way->dst); + p+=sizeof(float); + + for(i=0;i<30;++i) *p++ = way->name[i]; + for(i=0;i<24;++i) *p++ = way->city[i]; + for(i=0;i<2;++i) *p++ = way->state[i]; + + GPS_Util_Put_Short(p,way->alt); + p+=sizeof(int16); + + for(i=0;i<2;++i) *p++ = way->cc[i]; + *p++ = 0; + + if(way->wpt_class == 3) way->wpt_class = 0; + *p = way->wpt_class; + + *len = 124; + + return; +} + + + +/* @funcstatic GPS_D152_Send ******************************************** +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D152_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + GPS_Util_Put_Float(p,way->dst); + p+=sizeof(float); + + for(i=0;i<30;++i) *p++ = way->name[i]; + for(i=0;i<24;++i) *p++ = way->city[i]; + for(i=0;i<2;++i) *p++ = way->state[i]; + + GPS_Util_Put_Short(p,way->alt); + p+=sizeof(int16); + + for(i=0;i<2;++i) *p++ = way->cc[i]; + *p++ = 0; + + if(way->wpt_class == 5) way->wpt_class = 0; + *p = way->wpt_class; + + *len = 124; + + return; +} + + +/* @funcstatic GPS_D154_Send ******************************************* +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D154_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + GPS_Util_Put_Float(p,way->dst); + p+=sizeof(float); + + for(i=0;i<30;++i) *p++ = way->name[i]; + for(i=0;i<24;++i) *p++ = way->city[i]; + for(i=0;i<2;++i) *p++ = way->state[i]; + + GPS_Util_Put_Short(p,way->alt); + p+=sizeof(int16); + + for(i=0;i<2;++i) *p++ = way->cc[i]; + *p++ = 0; + + if(way->wpt_class == 9) way->wpt_class = 0; + *p++ = way->wpt_class; + + GPS_Util_Put_Short(p,(int16)way->smbl); + + *len = 126; + + return; +} + + + +/* @funcstatic GPS_D155_Send ******************************************* +** +** Form waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D155_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + GPS_Util_Put_Float(p,way->dst); + p+=sizeof(float); + + for(i=0;i<30;++i) *p++ = way->name[i]; + for(i=0;i<24;++i) *p++ = way->city[i]; + for(i=0;i<2;++i) *p++ = way->state[i]; + + GPS_Util_Put_Short(p,way->alt); + p+=sizeof(int16); + + for(i=0;i<2;++i) *p++ = way->cc[i]; + *p++ = 0; + + if(way->wpt_class == 5) way->wpt_class = 0; + *p++ = way->wpt_class; + + GPS_Util_Put_Short(p,(int16)way->smbl); + p+=sizeof(int16); + + *p = way->dspl; + + *len = 127; + + return; +} + + + +/* @func GPS_A200_Get ****************************************************** +** +** Get route data from GPS +** +** @param [r] port [const char *] serial port +** @param [w] way [GPS_PWay **] waypoint array +** +** @return [int32] number of waypoint entries +************************************************************************/ +int32 GPS_A200_Get(const char *port, GPS_PWay **way) +{ + static UC data[2]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 n; + int32 i; + + + if(!GPS_Serial_On(port,&fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Transfer_Rte); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_errno; + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + n = GPS_Util_Get_Short(rec->data); + + if(n) + if(!((*way)=(GPS_PWay *)malloc(n*sizeof(GPS_PWay)))) + { + GPS_Error("A200_Get: Insufficient memory"); + return MEMORY_ERROR; + } + + + for(i=0;itype == LINK_ID[gps_link_type].Pid_Rte_Hdr) + { + switch(gps_rte_hdr_type) + { + case pD200: + GPS_D200_Get(&((*way)[i]),rec->data); + break; + case pD201: + GPS_D201_Get(&((*way)[i]),rec->data); + break; + case pD202: + GPS_D202_Get(&((*way)[i]),rec->data); + break; + default: + GPS_Error("A200_GET: Unknown route protocol"); + return PROTOCOL_ERROR; + } + continue; + } + + if(rec->type != LINK_ID[gps_link_type].Pid_Rte_Wpt_Data) + { + GPS_Error("A200_GET: Non Pid_rte_Wpt_Data"); + return FRAMING_ERROR; + } + + (*way)[i]->isrte = 0; + (*way)[i]->islink = 0; + + switch(gps_rte_type) + { + case pD100: + GPS_D100_Get(&((*way)[i]),rec->data); + break; + case pD101: + GPS_D101_Get(&((*way)[i]),rec->data); + break; + case pD102: + GPS_D102_Get(&((*way)[i]),rec->data); + break; + case pD103: + GPS_D103_Get(&((*way)[i]),rec->data); + break; + case pD104: + GPS_D104_Get(&((*way)[i]),rec->data); + break; + case pD105: + GPS_D105_Get(&((*way)[i]),rec->data); + break; + case pD106: + GPS_D106_Get(&((*way)[i]),rec->data); + break; + case pD107: + GPS_D107_Get(&((*way)[i]),rec->data); + break; + case pD108: + GPS_D108_Get(&((*way)[i]),rec->data); + break; + case pD109: + GPS_D109_Get(&((*way)[i]),rec->data); + break; + case pD150: + GPS_D150_Get(&((*way)[i]),rec->data); + break; + case pD151: + GPS_D151_Get(&((*way)[i]),rec->data); + break; + case pD152: + GPS_D152_Get(&((*way)[i]),rec->data); + break; + case pD154: + GPS_D154_Get(&((*way)[i]),rec->data); + break; + case pD155: + GPS_D155_Get(&((*way)[i]),rec->data); + break; + default: + GPS_Error("A200_GET: Unknown route protocol"); + return PROTOCOL_ERROR; + } + (*way)[i-1]->prot = (*way)[i]->prot; + } + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("A200_GET: Error transferring routes"); + return FRAMING_ERROR; + } + + if(i != n) + { + GPS_Error("A200_GET: Route entry number mismatch"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return n; +} + + + +/* @func GPS_A201_Get ****************************************************** +** +** Get route data from GPS +** +** @param [r] port [const char *] serial port +** @param [w] way [GPS_PWay **] waypoint array +** +** @return [int32] number of waypoint entries +************************************************************************/ +int32 GPS_A201_Get(const char *port, GPS_PWay **way) +{ + static UC data[2]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 n; + int32 i; + + + if(!GPS_Serial_On(port,&fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Transfer_Rte); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_errno; + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + n = GPS_Util_Get_Short(rec->data); + + if(n) + if(!((*way)=(GPS_PWay *)malloc(n*sizeof(GPS_PWay)))) + { + GPS_Error("A201_Get: Insufficient memory"); + return MEMORY_ERROR; + } + + + for(i=0;itype == LINK_ID[gps_link_type].Pid_Rte_Hdr) + { + switch(gps_rte_hdr_type) + { + case pD200: + GPS_D200_Get(&((*way)[i]),rec->data); + break; + case pD201: + GPS_D201_Get(&((*way)[i]),rec->data); + break; + case pD202: + GPS_D202_Get(&((*way)[i]),rec->data); + break; + default: + GPS_Error("A201_GET: Unknown route protocol"); + return PROTOCOL_ERROR; + } + (*way)[i]->islink = 0; + continue; + } + + + if(rec->type == LINK_ID[gps_link_type].Pid_Rte_Link_Data) + { + switch(gps_rte_link_type) + { + case pD210: + GPS_D210_Get(&((*way)[i]),rec->data); + break; + default: + GPS_Error("A201_GET: Unknown route protocol"); + return PROTOCOL_ERROR; + } + (*way)[i]->isrte = 0; + (*way)[i]->islink = 1; + continue; + } + + if(rec->type != LINK_ID[gps_link_type].Pid_Rte_Wpt_Data) + { + GPS_Error("A200_GET: Non Pid_rte_Wpt_Data"); + return FRAMING_ERROR; + } + + (*way)[i]->isrte = 0; + (*way)[i]->islink = 0; + + switch(gps_rte_type) + { + case pD100: + GPS_D100_Get(&((*way)[i]),rec->data); + break; + case pD101: + GPS_D101_Get(&((*way)[i]),rec->data); + break; + case pD102: + GPS_D102_Get(&((*way)[i]),rec->data); + break; + case pD103: + GPS_D103_Get(&((*way)[i]),rec->data); + break; + case pD104: + GPS_D104_Get(&((*way)[i]),rec->data); + break; + case pD105: + GPS_D105_Get(&((*way)[i]),rec->data); + break; + case pD106: + GPS_D106_Get(&((*way)[i]),rec->data); + break; + case pD107: + GPS_D107_Get(&((*way)[i]),rec->data); + break; + case pD108: + GPS_D108_Get(&((*way)[i]),rec->data); + break; + case pD109: + GPS_D109_Get(&((*way)[i]),rec->data); + break; + case pD150: + GPS_D150_Get(&((*way)[i]),rec->data); + break; + case pD151: + GPS_D151_Get(&((*way)[i]),rec->data); + break; + case pD152: + GPS_D152_Get(&((*way)[i]),rec->data); + break; + case pD154: + GPS_D154_Get(&((*way)[i]),rec->data); + break; + case pD155: + GPS_D155_Get(&((*way)[i]),rec->data); + break; + default: + GPS_Error("A200_GET: Unknown route protocol"); + return PROTOCOL_ERROR; + } + (*way)[i-1]->prot = (*way)[i]->prot; + } + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("A200_GET: Error transferring routes"); + return FRAMING_ERROR; + } + + if(i != n) + { + GPS_Error("A200_GET: Route entry number mismatch"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return n; +} + + + +/* @func GPS_A200_Send ************************************************** +** +** Send routes to GPS +** +** @param [r] port [const char *] serial port +** @param [r] trk [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** +** @return [int32] success +************************************************************************/ +int32 GPS_A200_Send(const char *port, GPS_PWay *way, int32 n) +{ + UC data[GPS_ARB_LEN]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 i; + int32 len; + UC method; + + if(!GPS_Serial_On(port,&fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Util_Put_Short(data,n); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Records, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A200_Send: Route start data not acknowledged"); + return FRAMING_ERROR; + } + + + for(i=0;iisrte) + { + method = LINK_ID[gps_link_type].Pid_Rte_Hdr; + + switch(gps_rte_hdr_type) + { + case pD200: + GPS_D200_Send(data,way[i],&len); + break; + case pD201: + GPS_D201_Send(data,way[i],&len); + break; + case pD202: + GPS_D202_Send(data,way[i],&len); + break; + default: + GPS_Error("A200_Send: Unknown route protocol"); + return PROTOCOL_ERROR; + } + } + else + { + method = LINK_ID[gps_link_type].Pid_Rte_Wpt_Data; + + switch(gps_rte_type) + { + case pD100: + GPS_D100_Send(data,way[i],&len); + break; + case pD101: + GPS_D101_Send(data,way[i],&len); + break; + case pD102: + GPS_D102_Send(data,way[i],&len); + break; + case pD103: + GPS_D103_Send(data,way[i],&len); + break; + case pD104: + GPS_D104_Send(data,way[i],&len); + break; + case pD105: + GPS_D105_Send(data,way[i],&len); + break; + case pD106: + GPS_D106_Send(data,way[i],&len); + break; + case pD107: + GPS_D107_Send(data,way[i],&len); + break; + case pD108: + GPS_D108_Send(data,way[i],&len); + break; + case pD150: + GPS_D150_Send(data,way[i],&len); + break; + case pD151: + GPS_D151_Send(data,way[i],&len); + break; + case pD152: + GPS_D152_Send(data,way[i],&len); + break; + case pD154: + GPS_D154_Send(data,way[i],&len); + break; + case pD155: + GPS_D155_Send(data,way[i],&len); + break; + default: + GPS_Error("A200_Send: Unknown route protocol"); + return PROTOCOL_ERROR; + } + } + + + GPS_Make_Packet(&tra, method, data,len); + + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A200_Send: Route packet not acknowledged"); + return FRAMING_ERROR; + } + } + + GPS_Util_Put_Short(data,COMMAND_ID[gps_device_command].Cmnd_Transfer_Wpt); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Xfer_Cmplt, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A200_Send: Route complete data not acknowledged"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return 1; +} + + + +/* @func GPS_A201_Send ************************************************** +** +** Send routes to GPS +** +** @param [r] port [const char *] serial port +** @param [r] trk [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** +** @return [int32] success +************************************************************************/ +int32 GPS_A201_Send(const char *port, GPS_PWay *way, int32 n) +{ + UC data[GPS_ARB_LEN]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 i; + int32 len; + UC method; + + if(!GPS_Serial_On(port,&fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Util_Put_Short(data,n); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Records, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A200_Send: Route start data not acknowledged"); + return FRAMING_ERROR; + } + + + for(i=0;iisrte) + { + method = LINK_ID[gps_link_type].Pid_Rte_Hdr; + + switch(gps_rte_hdr_type) + { + case pD200: + GPS_D200_Send(data,way[i],&len); + break; + case pD201: + GPS_D201_Send(data,way[i],&len); + break; + case pD202: + GPS_D202_Send(data,way[i],&len); + break; + default: + GPS_Error("A200_Send: Unknown route protocol"); + return PROTOCOL_ERROR; + } + } + else if(way[i]->islink) + { + method = LINK_ID[gps_link_type].Pid_Rte_Link_Data; + + switch(gps_rte_link_type) + { + case pD210: + GPS_D210_Send(data,way[i],&len); + break; + default: + GPS_Error("A201_Send: Unknown route protocol"); + return PROTOCOL_ERROR; + } + } + else + { + method = LINK_ID[gps_link_type].Pid_Rte_Wpt_Data; + + switch(gps_rte_type) + { + case pD100: + GPS_D100_Send(data,way[i],&len); + break; + case pD101: + GPS_D101_Send(data,way[i],&len); + break; + case pD102: + GPS_D102_Send(data,way[i],&len); + break; + case pD103: + GPS_D103_Send(data,way[i],&len); + break; + case pD104: + GPS_D104_Send(data,way[i],&len); + break; + case pD105: + GPS_D105_Send(data,way[i],&len); + break; + case pD106: + GPS_D106_Send(data,way[i],&len); + break; + case pD107: + GPS_D107_Send(data,way[i],&len); + break; + case pD108: + GPS_D108_Send(data,way[i],&len); + break; + case pD109: + GPS_D109_Send(data,way[i],&len); + break; + case pD150: + GPS_D150_Send(data,way[i],&len); + break; + case pD151: + GPS_D151_Send(data,way[i],&len); + break; + case pD152: + GPS_D152_Send(data,way[i],&len); + break; + case pD154: + GPS_D154_Send(data,way[i],&len); + break; + case pD155: + GPS_D155_Send(data,way[i],&len); + break; + default: + GPS_Error("A200_Send: Unknown route protocol"); + return PROTOCOL_ERROR; + } + } + + + GPS_Make_Packet(&tra, method, data,len); + + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A200_Send: Route packet not acknowledged"); + return FRAMING_ERROR; + } + } + + GPS_Util_Put_Short(data,COMMAND_ID[gps_device_command].Cmnd_Transfer_Wpt); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Xfer_Cmplt, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A200_Send: Route complete data not acknowledged"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return 1; +} + + + + + +/* @funcstatic GPS_D200_Get ******************************************** +** +** Get route header data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D200_Get(GPS_PWay *way, UC *s) +{ + (*way)->rte_prot = 200; + (*way)->rte_num = *s; + (*way)->isrte = 1; + + return; +} + + + +/* @funcstatic GPS_D201_Get ******************************************* +** +** Get route header data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D201_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->rte_prot = 201; + (*way)->rte_num = *p++; + (*way)->isrte = 1; + for(i=0;i<20;++i) (*way)->rte_cmnt[i] = *p++; + + return; +} + + + +/* @funcstatic GPS_D202_Get ******************************************** +** +** Get route header data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D202_Get(GPS_PWay *way, UC *s) +{ + UC *p; + UC *q; + + p=s; + + (*way)->rte_prot = 201; +#if 0 + /* D202 has only a null terminated string for rte_ident */ + (*way)->rte_num = *p++; +#endif + (*way)->isrte = 1; + q = (UC *) (*way)->rte_ident; + while((*q++=*p++)); + + return; +} + + + +/* @funcstatic GPS_D210_Get ******************************************** +** +** Get route link data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D210_Get(GPS_PWay *way, UC *s) +{ + UC *p; + UC *q; + int32 i; + + p=s; + + (*way)->rte_link_class = GPS_Util_Get_Short(p); + p+=sizeof(int16); + for(i=0;i<18;++i) (*way)->rte_link_subclass[i] = *p++; + q = (UC *) (*way)->rte_link_ident; + while((*q++=*p++)); + + return; +} + + + +/* @funcstatic GPS_D200_Send ******************************************* +** +** Form route header data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D200_Send(UC *data, GPS_PWay way, int32 *len) +{ + + *data = way->rte_num; + *len = 1; + + return; +} + + + +/* @funcstatic GPS_D201_Send ******************************************* +** +** Form route header data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D201_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + *p++ = way->rte_num; + for(i=0;i<20;++i) *p++ = way->rte_cmnt[i]; + *len = 21; + + return; +} + + + +/* @funcstatic GPS_D202_Send ******************************************** +** +** Form route header data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D202_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + UC *q; + + p = data; + q = (UC *) way->rte_ident; + + while((*p++ = *q++)); + + *len = p-data; + + return; +} + + + +/* @funcstatic GPS_D210_Send ******************************************** +** +** Form route link data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D210_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + UC *q; + int32 i; + + p = data; + + GPS_Util_Put_Short(p,way->rte_link_class); + p+=sizeof(int16); + for(i=0;i<18;++i) *p++ = way->rte_link_subclass[i]; + + q = (UC *) way->rte_link_ident; + while((*p++ = *q++)); + + *len = p-data; + + return; +} + + + +/* @func GPS_A300_Get ****************************************************** +** +** Get track data from GPS +** +** @param [r] port [const char *] serial port +** @param [w] trk [GPS_PTrack **] track array +** +** @return [int32] number of track entries +************************************************************************/ +int32 GPS_A300_Get(const char *port, GPS_PTrack **trk) +{ + static UC data[2]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 n; + int32 i; + int32 ret; + + + if(gps_trk_transfer == -1) + return GPS_UNSUPPORTED; + + /* Only those GPS' with L001 can send track data */ + if(!LINK_ID[gps_link_type].Pid_Trk_Data) + { + GPS_Warning("A300 protocol unsupported"); + return GPS_UNSUPPORTED; + } + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Transfer_Trk); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_errno; + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + + n = GPS_Util_Get_Short(rec->data); + + if(n) + if(!((*trk)=(GPS_PTrack *)malloc(n*sizeof(GPS_PTrack)))) + { + GPS_Error("A300_Get: Insufficient memory"); + return MEMORY_ERROR; + } + for(i=0;idata); + + if(n) + if(!((*trk)=(GPS_PTrack *)malloc(n*sizeof(GPS_PTrack)))) + { + GPS_Error("A301_Get: Insufficient memory"); + return MEMORY_ERROR; + } + for(i=0;itype == LINK_ID[gps_link_type].Pid_Trk_Hdr) + { + switch(gps_trk_hdr_type) + { + case pD310: + case pD312: + GPS_D310_Get(&((*trk)[i]),rec->data); + break; + case pD311: + GPS_D311_Get(&((*trk)[i]),rec->data); + break; + default: + GPS_Error("A301_Get: Unknown track protocol"); + return PROTOCOL_ERROR; + } + (*trk)[i]->ishdr = 1; + continue; + } + + if(rec->type != LINK_ID[gps_link_type].Pid_Trk_Data) + { + GPS_Error("A301_Get: Non-Pid_Trk_Data"); + return FRAMING_ERROR; + } + + (*trk)[i]->ishdr = 0; + + switch(gps_trk_type) + { + case pD300: + GPS_D300b_Get(&((*trk)[i]),rec->data); + break; + case pD301: + GPS_D301b_Get(&((*trk)[i]),rec->data); + break; + case pD302: + GPS_D302b_Get(&((*trk)[i]),rec->data); + break; + default: + GPS_Error("A301_GET: Unknown track protocol"); + return PROTOCOL_ERROR; + } + } + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("A301_Get: Error transferring tracks"); + return FRAMING_ERROR; + } + + if(i != n) + { + GPS_Error("A301_GET: Track entry number mismatch"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return n; +} + + + + + +/* @func GPS_A300_Send ************************************************** +** +** Send track log to GPS +** +** @param [r] port [const char *] serial port +** @param [r] trk [GPS_PTrack *] track array +** @param [r] n [int32] number of track entries +** +** @return [int32] success +************************************************************************/ +int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n) +{ + UC data[GPS_ARB_LEN]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 i; + int32 len; + + if(gps_trk_transfer == -1) + return GPS_UNSUPPORTED; + + /* Only those GPS' with L001 can send track data */ + if(!LINK_ID[gps_link_type].Pid_Trk_Data) + { + GPS_Warning("A300 protocol unsupported"); + return GPS_UNSUPPORTED; + } + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Util_Put_Short(data,n); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Records, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A300_Send: Track start data not acknowledged"); + return FRAMING_ERROR; + } + + for(i=0;iishdr) + { + method = LINK_ID[gps_link_type].Pid_Trk_Hdr; + + switch(gps_trk_hdr_type) + { + case pD310: + case pD312: + GPS_D310_Send(data,trk[i],&len); + break; + default: + GPS_Error("A301_Send: Unknown track protocol"); + return PROTOCOL_ERROR; + } + } + else + { + method = LINK_ID[gps_link_type].Pid_Trk_Data; + + switch(gps_trk_type) + { + case pD300: + GPS_D300_Send(data,trk[i]); + len = 13; + break; + case pD301: + case pD302: + GPS_D301_Send(data,trk[i]); + len = 21; + break; + default: + GPS_Error("A301_Send: Unknown track protocol"); + return PROTOCOL_ERROR; + } + } + + + GPS_Make_Packet(&tra, method, data,len); + + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A301_Send: Track packet not acknowledgedn"); + return FRAMING_ERROR; + } + } + + + GPS_Util_Put_Short(data,COMMAND_ID[gps_device_command].Cmnd_Transfer_Trk); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Xfer_Cmplt, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A301_Send: Track complete data not acknowledged"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return 1; +} + + + +/* @func GPS_D300_Get ****************************************************** +** +** Get track data +** +** @param [w] trk [GPS_PTrack *] track array +** @param [r] entries [int32] number of packets to receive +** @param [r] fd [int32] file descriptor +** +** @return [int32] number of entries read +************************************************************************/ +int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, int32 fd) +{ + GPS_PPacket tra; + GPS_PPacket rec; + int32 i; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + for(i=0;idata, &trk[i]); + } + + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("D300_GET: Error transferring track log"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + return i; +} + + + +/* @func GPS_D300b_Get ****************************************************** +** +** Get track data (A301 protocol) +** +** @param [w] trk [GPS_PTrack *] track +** @param [r] data [UC *] packet data +** +** @return [void] +************************************************************************/ +void GPS_D300b_Get(GPS_PTrack *trk, UC *data) +{ + + GPS_A300_Translate(data, trk); + return; +} + + + +/* @func GPS_D301b_Get ****************************************************** +** +** Get track data (A301 protocol) +** +** @param [w] trk [GPS_PTrack *] track +** @param [r] data [UC *] packet data +** +** @return [void] +************************************************************************/ +void GPS_D301b_Get(GPS_PTrack *trk, UC *data) +{ + UC *p; + uint32 t; + + p=data; + + (*trk)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*trk)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + t = GPS_Util_Get_Uint(p); + if(!t || t==0x7fffffff || t==0xffffffff) + (*trk)->Time=0; + else + (*trk)->Time = GPS_Math_Gtime_To_Utime((time_t)t); + p+=sizeof(uint32); + + (*trk)->alt = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*trk)->dpth = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*trk)->tnew = *p; + + return; +} + +/* @func GPS_D302b_Get ****************************************************** +** +** Get track data (A301 protocol) +** +** @param [w] trk [GPS_PTrack *] track +** @param [r] data [UC *] packet data +** +** @return [void] +************************************************************************/ +void GPS_D302b_Get(GPS_PTrack *trk, UC *data) +{ + UC *p; + uint32 t; + double temp; + + p=data; + + (*trk)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*trk)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + t = GPS_Util_Get_Uint(p); + if(!t || t==0x7fffffff || t==0xffffffff) + (*trk)->Time=0; + else + (*trk)->Time = GPS_Math_Gtime_To_Utime((time_t)t); + p+=sizeof(uint32); + + (*trk)->alt = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*trk)->dpth = GPS_Util_Get_Float(p); + p+=sizeof(float); + + /* The only difference between 302 and 301 is the presence of temp + * in the middle. Nice planning, eh? + */ + temp = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*trk)->tnew = *p; + + return; +} + + +/* @func GPS_D310_Get ****************************************************** +** +** Get track header data (A301 protocol) +** +** @param [w] trk [GPS_PTrack *] track +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +void GPS_D310_Get(GPS_PTrack *trk, UC *s) +{ + UC *p; + UC *q; + + p=s; + + (*trk)->dspl = *p++; + (*trk)->colour = *p++; + + q = (UC *) (*trk)->trk_ident; + + while((*q++ = *p++)); + + return; +} + +/* @func GPS_D311_Get ****************************************************** +** +** Get track header data (A301 protocol) +** +** @param [w] trk [GPS_PTrack *] track +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +void GPS_D311_Get(GPS_PTrack *trk, UC *s) +{ + UC *p; + UC *q; + short identifier; + + p=s; + + /* Forerunner */ + identifier = GPS_Util_Get_Short(s); + sprintf((*trk)->trk_ident, "%d", identifier); + + return; +} + + +/* @func GPS_D300_Send ************************************************** +** +** Form track data string +** +** @param [w] data [UC *] string to write to +** @param [r] trk [GPS_PTrack] track data +** +** @return [void] +************************************************************************/ +void GPS_D300_Send(UC *data, GPS_PTrack trk) +{ + UC *p; + + p = data; + GPS_A300_Encode(p,trk); + + return; +} + + + +/* @func GPS_D301_Send ************************************************** +** +** Form track data string +** +** @param [w] data [UC *] string to write to +** @param [r] trk [GPS_PTrack] track data +** +** @return [void] +************************************************************************/ +void GPS_D301_Send(UC *data, GPS_PTrack trk) +{ + UC *p; + + p = data; + GPS_A300_Encode(p,trk); + p = data+12; + + GPS_Util_Put_Float(p,trk->alt); + p+=sizeof(float); + GPS_Util_Put_Float(p,trk->dpth); + p+=sizeof(float); + + *p = trk->tnew; + + return; +} + + + +/* @func GPS_D310_Send ************************************************** +** +** Form track header data string +** +** @param [w] data [UC *] string to write to +** @param [r] trk [GPS_PTrack] track data +** @param [w] len [int32 *] length of data +** +** @return [void] +************************************************************************/ +void GPS_D310_Send(UC *data, GPS_PTrack trk, int32 *len) +{ + UC *p; + UC *q; + + p = data; + + *p++ = trk->dspl; + *p++ = trk->colour; + + q = (UC *) trk->trk_ident; + while((*p++ = *q++)); + + *len = p-data; + + return; +} + + +/* @funcstatic GPS_A300_Translate *************************************** +** +** Translate track packet to track structure +** +** @param [r] s [const UC *] track packet data +** @param [w] trk [GPS_PTrack *] track entry pointer +** +** @return [void] +************************************************************************/ +static void GPS_A300_Translate(UC *s, GPS_PTrack *trk) +{ + UC *p; + uint32 t; + + p=s; + + (*trk)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*trk)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + t = GPS_Util_Get_Uint(p); + if(!t || t==0x7fffffff || t==0xffffffff) + (*trk)->Time=0; + else + (*trk)->Time = GPS_Math_Gtime_To_Utime((time_t)t); + p+=sizeof(uint32); + + (*trk)->tnew = *p; + + return; +} + + + +/* @funcstatic GPS_A300_Encode *************************************** +** +** Encode track structure to track packet +** +** @param [w] s [UC *] string to write to +** @param [r] trk [GPS_PTrack] track entry +** +** @return [void] +************************************************************************/ +static void GPS_A300_Encode(UC *s, GPS_PTrack trk) +{ + UC *p; + + p=s; + + GPS_Util_Put_Int(p,GPS_Math_Deg_To_Semi(trk->lat)); + p+=sizeof(int32); + + GPS_Util_Put_Int(p,GPS_Math_Deg_To_Semi(trk->lon)); + p+=sizeof(int32); + + GPS_Util_Put_Uint(p,GPS_Math_Utime_To_Gtime(trk->Time)); + p+=sizeof(uint32); + + *p = (UC) trk->tnew; + + return; +} + + + +/* @func GPS_A400_Get ************************************************** +** +** Get proximity waypoint data from GPS +** +** @param [r] port [const char *] serial port +** @param [w] way [GPS_PWay **] waypoint array +** +** @return [int32] number of waypoint entries +************************************************************************/ +int32 GPS_A400_Get(const char *port, GPS_PWay **way) +{ + static UC data[2]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 n; + int32 i; + + if(gps_prx_waypt_transfer == -1) + return GPS_UNSUPPORTED; + + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Transfer_Prx); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_errno; + + if(!GPS_Serial_Chars_Ready(fd)) + { + GPS_Warning("A400 (ppx) protocol not supported"); + GPS_Packet_Del(&rec); + GPS_Packet_Del(&tra); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return GPS_UNSUPPORTED; + } + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + n = GPS_Util_Get_Short(rec->data); + + if(n) + if(!((*way)=(GPS_PWay *)malloc(n*sizeof(GPS_PWay)))) + { + GPS_Error("A400_Get: Insufficient memory"); + return MEMORY_ERROR; + } + + + for(i=0;idata); + break; + case pD101: + GPS_D101_Get(&((*way)[i]),rec->data); + break; + case pD102: + GPS_D102_Get(&((*way)[i]),rec->data); + break; + case pD403: + GPS_D403_Get(&((*way)[i]),rec->data); + break; + case pD104: + GPS_D104_Get(&((*way)[i]),rec->data); + break; + case pD105: + GPS_D105_Get(&((*way)[i]),rec->data); + break; + case pD106: + GPS_D106_Get(&((*way)[i]),rec->data); + break; + case pD107: + GPS_D107_Get(&((*way)[i]),rec->data); + break; + case pD108: + GPS_D108_Get(&((*way)[i]),rec->data); + break; + case pD109: + GPS_D109_Get(&((*way)[i]),rec->data); + break; + case pD450: + GPS_D450_Get(&((*way)[i]),rec->data); + break; + case pD151: + GPS_D151_Get(&((*way)[i]),rec->data); + break; + case pD152: + GPS_D152_Get(&((*way)[i]),rec->data); + break; + case pD154: + GPS_D154_Get(&((*way)[i]),rec->data); + break; + case pD155: + GPS_D155_Get(&((*way)[i]),rec->data); + break; + default: + GPS_Error("A400_GET: Unknown prx waypoint protocol"); + return PROTOCOL_ERROR; + } + } + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("A400_GET: Error transferring prx waypoints"); + return FRAMING_ERROR; + } + + if(i != n) + { + GPS_Error("A400_GET: Prx waypoint entry number mismatch"); + return FRAMING_ERROR; + } + + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return n; +} + + + +/* @func GPS_A400_Send ************************************************** +** +** Send proximity waypoints to GPS +** +** @param [r] port [const char *] serial port +** @param [r] trk [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** +** @return [int32] success +************************************************************************/ +int32 GPS_A400_Send(const char *port, GPS_PWay *way, int32 n) +{ + UC data[GPS_ARB_LEN]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 i; + int32 len; + + if(gps_prx_waypt_transfer == -1) + return GPS_UNSUPPORTED; + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + GPS_Util_Put_Short(data,n); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Records, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A400_Send: Prx start data not acknowledgedn"); + return FRAMING_ERROR; + } + + + for(i=0;iprot = 400; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->dst=GPS_Util_Get_Float(p); + + + return; +} + + +/* @funcstatic GPS_D403_Get ******************************************** +** +** Get proximity waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D403_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 403; + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + p+=sizeof(int32); + + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->smbl = *p++; + (*way)->dspl = *p++; + + (*way)->dst=GPS_Util_Get_Float(p); + + return; +} + + +/* @funcstatic GPS_D450_Get ******************************************** +** +** Get proximity waypoint data +** +** @param [w] way [GPS_PWay *] waypoint array +** @param [r] s [UC *] packet data +** +** @return [void] +************************************************************************/ +static void GPS_D450_Get(GPS_PWay *way, UC *s) +{ + UC *p; + int32 i; + + p=s; + + (*way)->prot = 450; + + (*way)->idx = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + for(i=0;i<6;++i) (*way)->ident[i] = *p++; + for(i=0;i<2;++i) (*way)->cc[i] = *p++; + (*way)->wpt_class = *p++; + + (*way)->lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->lon = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); + p+=sizeof(int32); + + (*way)->alt = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + for(i=0;i<24;++i) (*way)->city[i] = *p++; + for(i=0;i<2;++i) (*way)->state[i] = *p++; + for(i=0;i<30;++i) (*way)->name[i] = *p++; + for(i=0;i<40;++i) (*way)->cmnt[i] = *p++; + + (*way)->dst=GPS_Util_Get_Float(p); + + return; +} + + +/* @funcstatic GPS_D400_Send ******************************************** +** +** Form proximity waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D400_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + + GPS_Util_Put_Float(p,way->dst); + + *len = 62; + + return; +} + + +/* @funcstatic GPS_D403_Send ******************************************* +** +** Form proximity waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D403_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + for(i=0;i<6;++i) *p++ = way->ident[i]; + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + GPS_Util_Put_Uint(p,0); + p+=sizeof(int32); + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + + *p++ = way->smbl; + *p = way->dspl; + + GPS_Util_Put_Float(p,way->dst); + + *len = 64; + + return; +} + + +/* @funcstatic GPS_D450_Send ******************************************* +** +** Form proximity waypoint data string +** +** @param [w] data [UC *] string to write to +** @param [r] way [GPS_PWay] waypoint data +** @param [w] len [int32 *] packet length +** +** @return [void] +************************************************************************/ +static void GPS_D450_Send(UC *data, GPS_PWay way, int32 *len) +{ + UC *p; + int32 i; + + p = data; + + GPS_Util_Put_Short(p,way->idx); + p+=sizeof(int16); + + for(i=0;i<6;++i) *p++ = way->ident[i]; + for(i=0;i<2;++i) *p++ = way->cc[i]; + *p++ = way->wpt_class; + + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lat)); + p+=sizeof(int32); + GPS_Util_Put_Int(p,(int32)GPS_Math_Deg_To_Semi(way->lon)); + p+=sizeof(int32); + + GPS_Util_Put_Short(p,way->alt); + p+=sizeof(int16); + + for(i=0;i<24;++i) *p++ = way->city[i]; + for(i=0;i<2;++i) *p++ = way->state[i]; + for(i=0;i<30;++i) *p++ = way->name[i]; + for(i=0;i<40;++i) *p++ = way->cmnt[i]; + + GPS_Util_Put_Float(p,way->dst); + + + *len = 121; + + return; +} + + + +/* @func GPS_A500_Get ****************************************************** +** +** Get almanac from GPS +** +** @param [r] port [const char *] serial port +** @param [w] alm [GPS_PAlmanac **] almanac array +** +** @return [int32] number of almanac entries +************************************************************************/ +int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm) +{ + static UC data[2]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 n; + int32 i; + int32 ret; + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Transfer_Alm); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_errno; + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + n = GPS_Util_Get_Short(rec->data); + + if(n) + if(!((*alm)=(GPS_PAlmanac *)malloc(n*sizeof(GPS_PAlmanac)))) + { + GPS_Error("A500_Get: Insufficient memory"); + return MEMORY_ERROR; + } + for(i=0;itype == LINK_ID[gps_link_type].Pid_Command_Data && + GPS_Util_Get_Short(rec->data) == COMMAND_ID[gps_device_command]. + Cmnd_Transfer_Time) + { + GPS_User("INFO: GPS time request. Sending...."); + ret = GPS_Rqst_Send_Time(fd,gps_save_time); + if(ret < 0) return ret; + timesent=1; + } + } + + + + /* + * Allow GPS a little while to decide whether it wants to ask for + * the position. Note that the posn sent is held in gps_save_lat + * and gps_save_lon global! + */ + if(GPS_Serial_Wait(fd)) + { + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + if(rec->type == LINK_ID[gps_link_type].Pid_Command_Data && + GPS_Util_Get_Short(rec->data) == COMMAND_ID[gps_device_command]. + Cmnd_Transfer_Posn) + { + GPS_User("INFO: GPS position request. Sending...."); + ret = GPS_Rqst_Send_Position(fd,gps_save_lat,gps_save_lon); + if(ret < 0) return ret; + posnsent=1; + } + } + + if(!timesent) + { + ret = GPS_Rqst_Send_Time(fd,gps_save_time); + if(ret < 0) return ret; + } + + + if(!posnsent) + { + ret = GPS_Rqst_Send_Position(fd,gps_save_lat,gps_save_lon); + if(ret < 0) return ret; + } + + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return 1; +} + + + +/* @funcstatic GPS_D500_Get ******************************************** +** +** Get almanac data +** +** @param [w] alm [GPS_PAlmanac *] almanac array +** @param [r] entries [int32] number of packets to receive +** @param [r] fd [int32] file descriptor +** +** @return [int32] number of entries read +************************************************************************/ +static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) +{ + GPS_PPacket tra; + GPS_PPacket rec; + int32 i; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + for(i=0;idata, &alm[i]); + } + + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("D500_GET: Error transferring almanac"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + return i; +} + + +/* @funcstatic GPS_D501_Get ******************************************** +** +** Get almanac data +** +** @param [w] alm [GPS_PAlmanac *] almanac array +** @param [r] entries [int32] number of packets to receive +** @param [r] fd [int32] file descriptor +** +** @return [int32] number of entries read +************************************************************************/ +static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) +{ + GPS_PPacket tra; + GPS_PPacket rec; + int32 i; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + for(i=0;idata, &alm[i]); + alm[i]->hlth=rec->data[42]; + } + + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("D501_GET: Error transferring almanac"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + return i; +} + + + +/* @funcstatic GPS_D550_Get ********************************************* +** +** Get almanac data +** +** @param [w] alm [GPS_PAlmanac *] almanac array +** @param [r] entries [int32] number of packets to receive +** @param [r] fd [int32] file descriptor +** +** @return [int32] number of entries read +************************************************************************/ +static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) +{ + GPS_PPacket tra; + GPS_PPacket rec; + int32 i; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + for(i=0;isvid = rec->data[0]; + GPS_A500_Translate(rec->data+1, &alm[i]); + } + + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("D550_GET: Error transferring almanac"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + return i; +} + + + +/* @funcstatic GPS_D551_Get ********************************************* +** +** Get almanac data +** +** @param [w] alm [GPS_PAlmanac *] almanac array +** @param [r] entries [int32] number of packets to receive +** @param [r] fd [int32] file descriptor +** +** @return [int32] number of entries read +************************************************************************/ +static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) +{ + GPS_PPacket tra; + GPS_PPacket rec; + int32 i; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + for(i=0;isvid = rec->data[0]; + GPS_A500_Translate(rec->data+1, &alm[i]); + alm[i]->hlth = rec->data[43]; + } + + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("D551_GET: Error transferring almanac\n"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + return i; +} + + + +/* @funcstatic GPS_A500_Translate *************************************** +** +** Translate almanac packet to almanac structure +** +** @param [r] s [const UC *] almanac packet data +** @param [w] alm [GPS_PAlmanac *] almanac entry pointer +** +** @return [void] +************************************************************************/ +static void GPS_A500_Translate(UC *s, GPS_PAlmanac *alm) +{ + UC *p; + + p=s; + + (*alm)->wn = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + (*alm)->toa = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*alm)->af0 = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*alm)->af1 = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*alm)->e = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*alm)->sqrta = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*alm)->m0 = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*alm)->w = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*alm)->omg0 = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*alm)->odot = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*alm)->i = GPS_Util_Get_Float(p); + p+=sizeof(float); + + return; +} + + +/* @funcstatic GPS_D500_Send ******************************************* +** +** Form almanac data string +** +** @param [w] data [UC *] string to write to +** @param [r] alm [GPS_PAlmanac] almanac data +** +** @return [void] +************************************************************************/ +static void GPS_D500_Send(UC *data, GPS_PAlmanac alm) +{ + UC *p; + + p = data; + GPS_A500_Encode(p,alm); + + return; +} + + + +/* @funcstatic GPS_D501_Send ******************************************** +** +** Form almanac data string +** +** @param [w] data [UC *] string to write to +** @param [r] alm [GPS_PAlmanac] almanac data +** +** @return [void] +************************************************************************/ +static void GPS_D501_Send(UC *data, GPS_PAlmanac alm) +{ + UC *p; + + p=data; + p[42] = alm->hlth; + GPS_A500_Encode(p,alm); + + return; +} + + + +/* @funcstatic GPS_D550_Send ******************************************** +** +** Form almanac data string +** +** @param [w] data [UC *] string to write to +** @param [r] alm [GPS_PAlmanac] almanac data +** +** @return [void] +************************************************************************/ +static void GPS_D550_Send(UC *data, GPS_PAlmanac alm) +{ + UC *p; + + p = data; + *p = alm->svid; + GPS_A500_Encode(p+1,alm); + + return; +} + + + +/* @funcstatic GPS_D551_Send ******************************************** +** +** Form almanac data string +** +** @param [w] data [UC *] string to write to +** @param [r] alm [GPS_PAlmanac] almanac data +** +** @return [void] +************************************************************************/ +static void GPS_D551_Send(UC *data, GPS_PAlmanac alm) +{ + UC *p; + + p = data; + *p = alm->svid; + GPS_A500_Encode(p+1,alm); + p[43] = alm->hlth; + + return; +} + + + +/* @funcstatic GPS_A500_Encode *************************************** +** +** Encode almanac structure to almanac packet +** +** @param [w] s [UC *] string to write to +** @param [r] alm [GPS_PAlmanac] almanac entry +** +** @return [void] +************************************************************************/ +static void GPS_A500_Encode(UC *s, GPS_PAlmanac alm) +{ + UC *p; + + p=s; + + GPS_Util_Put_Short(p,alm->wn); + p+=sizeof(int16); + + GPS_Util_Put_Float(p,alm->toa); + p+=sizeof(float); + + GPS_Util_Put_Float(p,alm->af0); + p+=sizeof(float); + + GPS_Util_Put_Float(p,alm->af1); + p+=sizeof(float); + + GPS_Util_Put_Float(p,alm->e); + p+=sizeof(float); + + GPS_Util_Put_Float(p,alm->sqrta); + p+=sizeof(float); + + GPS_Util_Put_Float(p,alm->m0); + p+=sizeof(float); + + GPS_Util_Put_Float(p,alm->w); + p+=sizeof(float); + + GPS_Util_Put_Float(p,alm->omg0); + p+=sizeof(float); + + GPS_Util_Put_Float(p,alm->odot); + p+=sizeof(float); + + GPS_Util_Put_Float(p,alm->i); + + return; +} + + +/* @func GPS_A600_Get ****************************************************** +** +** Get time from GPS +** +** @param [r] port [const char *] serial port +** +** @return [time_t] GPS time as unix system time, -ve if error +************************************************************************/ +time_t GPS_A600_Get(const char *port) +{ + static UC data[2]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + time_t ret; + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Transfer_Time); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_errno; + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + switch(gps_date_time_type) + { + case pD600: + ret = GPS_D600_Get(rec); + break; + default: + GPS_Error("A600_Get: Unknown data/time protocol"); + return PROTOCOL_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return ret; +} + + + + + +/* @func GPS_A600_Send ************************************************** +** +** Send time to GPS +** +** @param [r] port [const char *] serial port +** @param [r] Time [time_t] unix-style time +** +** @return [int32] success +************************************************************************/ +int32 GPS_A600_Send(const char *port, time_t Time) +{ + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 posnsent=0; + int32 ret=0; + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + switch(gps_date_time_type) + { + case pD600: + GPS_D600_Send(&tra,Time); + break; + default: + GPS_Error("A600_Send: Unknown data/time protocol"); + return PROTOCOL_ERROR; + } + + if(!GPS_Write_Packet(fd,tra)) + return gps_error; + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_error; + + + /* + * Allow GPS a little while to decide whether it wants to ask for + * the position. Note that the posn sent is held in gps_save_lat + * and gps_save_lon globals! + */ + if(GPS_Serial_Wait(fd)) + { + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + if(rec->type == LINK_ID[gps_link_type].Pid_Command_Data && + GPS_Util_Get_Short(rec->data) == COMMAND_ID[gps_device_command]. + Cmnd_Transfer_Posn) + { + GPS_User("INFO: GPS position request. Sending...."); + ret = GPS_Rqst_Send_Position(fd,gps_save_lat,gps_save_lon); + if(ret < 0) return ret; + posnsent=1; + } + } + + + if(!posnsent) + { + ret = GPS_Rqst_Send_Position(fd,gps_save_lat,gps_save_lon); + if(ret < 0) return ret; + } + + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return 1; +} + + + + + +/* @func GPS_D600_Get ****************************************************** +** +** Convert date/time packet to ints +** +** @param [r] packet [GPS_PPacket] packet +** +** @return [time_t] gps time as unix system time +************************************************************************/ +time_t GPS_D600_Get(GPS_PPacket packet) +{ + UC *p; + static struct tm ts; + + p = packet->data; + + ts.tm_mon = *p++ - 1; + ts.tm_mday = *p++; + ts.tm_year = (int32) GPS_Util_Get_Short(p) - 1900; + p+=2; + ts.tm_hour = (int32) GPS_Util_Get_Short(p); + p+=2; + ts.tm_min = *p++; + ts.tm_sec = *p++; + + return mktime(&ts); +} + + +/* @func GPS_D600_Send ****************************************************** +** +** make a time packet for sending to the GPS +** +** @param [w] packet [GPS_PPacket *] packet +** @param [r] Time [time_t] unix-style time +** +** @return [void] +************************************************************************/ +void GPS_D600_Send(GPS_PPacket *packet, time_t Time) +{ + UC data[10]; + UC *p; + struct tm *ts; + + p = data; + + ts = localtime(&Time); + *p++ = ts->tm_mon+1; + *p++ = ts->tm_mday; + + GPS_Util_Put_Short(p,ts->tm_year+1900); + p+=2; + GPS_Util_Put_Short(p,ts->tm_hour); + p+=2; + + *p++ = ts->tm_min; + *p = ts->tm_sec; + + GPS_Make_Packet(packet, LINK_ID[gps_link_type].Pid_Date_Time_Data, + data,8); + + return; +} + + + + +/* @func GPS_A700_Get ****************************************************** +** +** Get position from GPS +** +** @param [r] port [const char *] serial port +** @param [w] lat [double *] latitude (deg) +** @param [w] lon [double *] longitude (deg) +** +** @return [int32] success +************************************************************************/ +int32 GPS_A700_Get(const char *port, double *lat, double *lon) +{ + static UC data[2]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Transfer_Posn); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_errno; + + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + switch(gps_position_type) + { + case pD700: + GPS_D700_Get(rec, lat, lon); + break; + default: + GPS_Error("A700_Get: Unknown position protocol"); + return PROTOCOL_ERROR; + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return 1; +} + + + +/* @func GPS_A700_Send ****************************************************** +** +** Send position to GPS +** +** @param [r] port [const char *] serial port +** @param [r] lat [double] latitude (deg) +** @param [r] lon [double] longitute (deg) +** +** @return [int32] success +************************************************************************/ +int32 GPS_A700_Send(const char *port, double lat, double lon) +{ + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + switch(gps_position_type) + { + case pD700: + GPS_D700_Send(&tra,lat,lon); + break; + default: + GPS_Error("A700_Send: Unknown position protocol"); + return PROTOCOL_ERROR; + } + + if(!GPS_Write_Packet(fd,tra)) + return 0; + if(!GPS_Get_Ack(fd, &tra, &rec)) + return 0; + + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return 1; +} + + + +/* @func GPS_D700_Get ****************************************************** +** +** Convert position packet to lat/long in degrees +** +** @param [r] packet [GPS_PPacket] packet +** @param [w] lat [double *] latitude (deg) +** @param [w] lon [double *] longitude (deg) +** +** @return [void] +************************************************************************/ +void GPS_D700_Get(GPS_PPacket packet, double *lat, double *lon) +{ + UC *p; + double t; + + p = packet->data; + + t = GPS_Util_Get_Double(p); + *lat = GPS_Math_Rad_To_Deg(t); + + p += sizeof(double); + + t = GPS_Util_Get_Double(p); + *lon = GPS_Math_Rad_To_Deg(t); + + + return; +} + + +/* @func GPS_D700_Send ****************************************************** +** +** make a position packet for sending to the GPS +** +** @param [w] packet [GPS_PPacket *] packet +** @param [r] lat [double] latitude (deg) +** @param [r] lon [double] longitude (deg) +** +** @return [void] +************************************************************************/ +void GPS_D700_Send(GPS_PPacket *packet, double lat, double lon) +{ + UC data[16]; + UC *p; + + lat = GPS_Math_Deg_To_Rad(lat); + lon = GPS_Math_Deg_To_Rad(lon); + + p = data; + + GPS_Util_Put_Double(p,lat); + p+=sizeof(double); + GPS_Util_Put_Double(p,lon); + + GPS_Make_Packet(packet, LINK_ID[gps_link_type].Pid_Position_Data, + data,16); + + return; +} + + + +/* @func GPS_A800_On ****************************************************** +** +** Turn on GPS PVT +** +** @param [r] port [const char *] serial port +** @param [w] fd [int32 *] file descriptor +** +** @return [int32] success +************************************************************************/ +int32 GPS_A800_On(const char *port, int32 *fd) +{ + static UC data[2]; + GPS_PPacket tra; + GPS_PPacket rec; + + if(!GPS_Serial_On(port, fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Start_Pvt_Data); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + if(!GPS_Write_Packet(*fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(*fd, &tra, &rec)) + { + GPS_Error("A800_on: Pvt start data not acknowledged"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&rec); + GPS_Packet_Del(&tra); + + return 1; +} + + + +/* @func GPS_A800_Off ****************************************************** +** +** Turn off GPS PVT +** +** @param [r] port [const char *] port +** @param [w] fd [int32 *] file descriptor +** +** @return [int32] success +************************************************************************/ +int32 GPS_A800_Off(const char *port, int32 *fd) +{ + static UC data[2]; + GPS_PPacket tra; + GPS_PPacket rec; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Stop_Pvt_Data); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + if(!GPS_Write_Packet(*fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(*fd, &tra, &rec)) + { + GPS_Error("A800_Off: Not acknowledged"); + return FRAMING_ERROR; + } + + + GPS_Packet_Del(&rec); + GPS_Packet_Del(&tra); + + if(!GPS_Serial_Off(port, *fd)) + return gps_errno; + + return 1; +} + + +/* @func GPS_A800_Get ************************************************** +** +** make a position packet for sending to the GPS +** +** @param [r] fd [int32 *] file descriptor +** @param [w] packet [GPS_PPvt_Data *] packet +** +** @return [int32] success +************************************************************************/ +int32 GPS_A800_Get(int32 *fd, GPS_PPvt_Data *packet) +{ + GPS_PPacket tra; + GPS_PPacket rec; + + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + if(!GPS_Packet_Read(*fd, &rec)) + return gps_errno; + + if(!GPS_Send_Ack(*fd, &tra, &rec)) + return gps_errno; + + switch(gps_pvt_type) + { + case pD800: + GPS_D800_Get(rec,packet); + break; + default: + GPS_Error("A800_GET: Unknown pvt protocol"); + return PROTOCOL_ERROR; + } + + GPS_Packet_Del(&rec); + GPS_Packet_Del(&tra); + + return 1; +} + + + +/* @func GPS_D800_Get ****************************************************** +** +** Convert packet to pvt structure +** +** @param [r] packet [GPS_PPacket] packet +** @param [w] pvt [GPS_PPvt_Data *] pvt structure +** +** @return [void] +************************************************************************/ +void GPS_D800_Get(GPS_PPacket packet, GPS_PPvt_Data *pvt) +{ + UC *p; + + p = packet->data; + + (*pvt)->alt = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*pvt)->epe = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*pvt)->eph = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*pvt)->epv = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*pvt)->fix = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + (*pvt)->tow = GPS_Util_Get_Double(p); + p+=sizeof(double); + + (*pvt)->lat = GPS_Math_Rad_To_Deg(GPS_Util_Get_Double(p)); + p+=sizeof(double); + + (*pvt)->lon = GPS_Math_Rad_To_Deg(GPS_Util_Get_Double(p)); + p+=sizeof(double); + + (*pvt)->east = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*pvt)->north = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*pvt)->up = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*pvt)->msl_hght = GPS_Util_Get_Float(p); + p+=sizeof(float); + + (*pvt)->leap_scnds = GPS_Util_Get_Short(p); + p+=sizeof(int16); + + (*pvt)->wn_days = GPS_Util_Get_Int(p); + + return; +} + + +/* + * It's unfortunate that these aren't constant and therefore switchable, + * but they really are runtime variable. Sigh. + */ + +const char * +Get_Pkt_Type(unsigned char p, unsigned char d0, const char **xinfo) +{ + *xinfo = NULL; +#define LT LINK_ID[gps_link_type] + if (p == LT.Pid_Ack_Byte) + return "ACK"; + if (p == LT.Pid_Command_Data) { + switch (d0) { + case 0: *xinfo = "Abort"; break; + case 1: *xinfo = "Xfer Alm"; break; + case 2: *xinfo = "Xfer Posn"; break; + case 3: *xinfo = "Xfer Prx"; break; + case 4: *xinfo = "Xfer Rte"; break; + case 5: *xinfo = "Xfer Time"; break; + case 6: *xinfo = "Xfer Trk"; break; + case 7: *xinfo = "Xfer Wpt"; break; + case 8: *xinfo = "Power Down"; break; + case 49: *xinfo = "Xfer PVT Start"; break; + case 50: *xinfo = "Xfer PVT Stop"; break; + case 92: *xinfo = "Flight Records"; break; + case 117: *xinfo = "Xfer Laps"; break; + default: *xinfo = "Unknown"; + } + return "CMDDAT"; + } + if (p == LT.Pid_Xfer_Cmplt) + return "XFRCMP"; + if (p == LT.Pid_Date_Time_Data) + return "DATTIM"; + if (p == LT.Pid_Position_Data) + return "POS"; + if (p == LT.Pid_Prx_Wpt_Data) + return "WPT"; + if (p == LT.Pid_Nak_Byte) + return "NAK"; + if (p == LT.Pid_Records) + return "RECORD"; + if (p == LT.Pid_Rte_Hdr) + return "RTEHDR"; + if (p == LT.Pid_Rte_Wpt_Data) + return "RTEWPT"; + if (p == LT.Pid_Almanac_Data) + return "RALMAN"; + if (p == LT.Pid_Trk_Data) + return "TRKDAT"; + if (p == LT.Pid_Wpt_Data) + return "WPTDAT"; + if (p == LT.Pid_Pvt_Data) + return "PVTDAT"; + if (p == LT.Pid_Rte_Link_Data) + return "LNKDAT"; + if (p == LT.Pid_Trk_Hdr) + return "TRKHDR"; + if (p == LT.Pid_Protocol_Array) + return "PRTARR"; + if (p == LT.Pid_Product_Rqst) + return "PRDREQ"; + if (p == LT.Pid_Product_Data) + return "PRDDAT"; + return "UNKNOWN"; +} diff --git a/jeeps/gpsapp.h b/jeeps/gpsapp.h new file mode 100644 index 000000000..4a36fdf4f --- /dev/null +++ b/jeeps/gpsapp.h @@ -0,0 +1,65 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsapp_h +#define gpsapp_h + + +#include "gps.h" + +int32 GPS_Init(const char *port); + +int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int ct, GPS_PWay *)); +int32 GPS_A100_Send(const char *port, GPS_PWay *way, int32 n, int (*cb)(GPS_PWay *)); + +int32 GPS_A200_Get(const char *port, GPS_PWay **way); +int32 GPS_A201_Get(const char *port, GPS_PWay **way); +int32 GPS_A200_Send(const char *port, GPS_PWay *way, int32 n); +int32 GPS_A201_Send(const char *port, GPS_PWay *way, int32 n); + +int32 GPS_A300_Get(const char *port, GPS_PTrack **trk); +int32 GPS_A301_Get(const char *port, GPS_PTrack **trk); +int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n); +int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n); + +int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, int32 fd); +void GPS_D300b_Get(GPS_PTrack *trk, UC *data); +void GPS_D301b_Get(GPS_PTrack *trk, UC *data); +void GPS_D302b_Get(GPS_PTrack *trk, UC *data); +void GPS_D310_Get(GPS_PTrack *trk, UC *s); +void GPS_D311_Get(GPS_PTrack *trk, UC *s); +void GPS_D300_Send(UC *data, GPS_PTrack trk); +void GPS_D301_Send(UC *data, GPS_PTrack trk); +void GPS_D310_Send(UC *data, GPS_PTrack trk, int32 *len); + +int32 GPS_A400_Get(const char *port, GPS_PWay **way); +int32 GPS_A400_Send(const char *port, GPS_PWay *way, int32 n); + +int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm); +int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n); + +time_t GPS_A600_Get(const char *port); +time_t GPS_D600_Get(GPS_PPacket packet); +int32 GPS_A600_Send(const char *port, time_t Time); +void GPS_D600_Send(GPS_PPacket *packet, time_t Time); + +int32 GPS_A700_Get(const char *port, double *lat, double *lon); +int32 GPS_A700_Send(const char *port, double lat, double lon); +void GPS_D700_Get(GPS_PPacket packet, double *lat, double *lon); +void GPS_D700_Send(GPS_PPacket *packet, double lat, double lon); + +int32 GPS_A800_On(const char *port, int32 *fd); +int32 GPS_A800_Off(const char *port, int32 *fd); +int32 GPS_A800_Get(int32 *fd, GPS_PPvt_Data *packet); +void GPS_D800_Get(GPS_PPacket packet, GPS_PPvt_Data *pvt); + +const char * Get_Pkt_Type(unsigned char p, unsigned char d0, const char **xinfo); + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpscom.c b/jeeps/gpscom.c new file mode 100644 index 000000000..9cfca0331 --- /dev/null +++ b/jeeps/gpscom.c @@ -0,0 +1,612 @@ +/******************************************************************** +** @source JEEPS command functions +** +** @author Copyright (C) 1999 Alan Bleasby +** @version 1.0 +** @modified Dec 28 1999 Alan Bleasby. First version +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include + + +/* @func GPS_Command_Off *********************************************** +** +** Turn off power on GPS +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Command_Off(const char *port) +{ + static UC data[2]; + int32 fd; + GPS_PPacket tra; + GPS_PPacket rec; + + GPS_Util_Little(); + + gps_is_usb = (0 == strncmp(port, "usb:", 4)); + + if(!GPS_Serial_On(port, &fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Util_Put_Short(data,COMMAND_ID[gps_device_command].Cmnd_Turn_Off_Pwr); + + /* robertl - LINK_ID isn't set yet. Hardcode it to Garmin spec value */ + GPS_Make_Packet(&tra, 10, /* LINK_ID[gps_link_type].Pid_Command_Data, */ + data,2); + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + + if(!GPS_Serial_Chars_Ready(fd)) + { + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_errno; + GPS_User("Power off command acknowledged"); + } + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + if(!GPS_Serial_Off(port, fd)) + return gps_errno; + + return 1; +} + + +/* @func GPS_Command_Get_Waypoint *************************************** +** +** Get waypoint from GPS +** +** @param [r] port [const char *] serial port +** @param [w] way [GPS_PWay **] pointer to waypoint array +** +** @return [int32] number of waypoint entries +************************************************************************/ + +int32 GPS_Command_Get_Waypoint(const char *port, GPS_PWay **way, int (*cb)()) +{ + int32 ret=0; + + switch(gps_waypt_transfer) + { + case pA100: + ret = GPS_A100_Get(port,way, cb); + break; + default: + GPS_Error("Get_Waypoint: Unknown waypoint protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + +/* @func GPS_Command_Send_Waypoint ****************************************** +** +** Send waypoints to GPS +** +** @param [r] port [const char *] serial port +** @param [r] way [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Command_Send_Waypoint(const char *port, GPS_PWay *way, int32 n, int (*cb)()) +{ + int32 ret=0; + + switch(gps_waypt_transfer) + { + case pA100: + ret = GPS_A100_Send(port, way, n, cb); + break; + default: + GPS_Error("Send_Waypoint: Unknown waypoint protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + +/* @func GPS_Command_Get_Route ************************************** +** +** Get Route(s) from GPS +** +** @param [r] port [const char *] serial port +** @param [w] way [GPS_PWay **] pointer to waypoint array +** +** @return [int32] number of waypoint entries +************************************************************************/ + +int32 GPS_Command_Get_Route(const char *port, GPS_PWay **way) +{ + int32 ret=0; + + switch(gps_route_transfer) + { + case pA200: + ret = GPS_A200_Get(port,way); + break; + case pA201: + ret = GPS_A201_Get(port,way); + break; + default: + GPS_Error("Get_Route: Unknown route protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + +/* @func GPS_Command_Send_Route **************************************** +** +** Send route(s) to GPS +** +** @param [r] port [const char *] serial port +** @param [r] way [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Command_Send_Route(const char *port, GPS_PWay *way, int32 n) +{ + int32 ret=0; + + + switch(gps_route_transfer) + { + case pA200: + ret = GPS_A200_Send(port, way, n); + break; + case pA201: + ret = GPS_A201_Send(port, way, n); + break; + default: + GPS_Error("Send_Route: Unknown route protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + +/* @func GPS_Command_Get_Track *************************************** +** +** Get track log from GPS +** +** @param [r] port [const char *] serial port +** @param [w] trk [GPS_PTrack **] pointer to track array +** +** @return [int32] number of track entries +************************************************************************/ + +int32 GPS_Command_Get_Track(const char *port, GPS_PTrack **trk) +{ + int32 ret=0; + + if(gps_trk_transfer == -1) + return GPS_UNSUPPORTED; + + switch(gps_trk_transfer) + { + case pA300: + ret = GPS_A300_Get(port,trk); + break; + case pA301: + case pA302: + ret = GPS_A301_Get(port,trk); + break; + default: + GPS_Error("Get_Track: Unknown track protocol\n"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + +/* @func GPS_Command_Send_Track ****************************************** +** +** Send track log to GPS +** +** @param [r] port [const char *] serial port +** @param [r] trk [GPS_PTrack *] track array +** @param [r] n [int32] number of track entries +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Command_Send_Track(const char *port, GPS_PTrack *trk, int32 n) +{ + int32 ret=0; + + if(gps_trk_transfer == -1) + return GPS_UNSUPPORTED; + + switch(gps_trk_transfer) + { + case pA300: + ret = GPS_A300_Send(port, trk, n); + break; + case pA301: + ret = GPS_A301_Send(port, trk, n); + break; + default: + GPS_Error("Send_Track: Unknown track protocol"); + break; + } + + return ret; +} + + +/* @func GPS_Command_Get_Proximity ************************************** +** +** Get proximitywaypoint from GPS +** +** @param [r] port [const char *] serial port +** @param [w] way [GPS_PWay **] pointer to waypoint array +** +** @return [int32] number of waypoint entries +************************************************************************/ + +int32 GPS_Command_Get_Proximity(const char *port, GPS_PWay **way) +{ + int32 ret=0; + + if(gps_prx_waypt_transfer == -1) + return GPS_UNSUPPORTED; + + switch(gps_prx_waypt_transfer) + { + case pA400: + ret = GPS_A400_Get(port,way); + break; + default: + GPS_Error("Get_Proximity: Unknown proximity protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + +/* @func GPS_Command_Send_Proximity ****************************************** +** +** Send proximity waypoints to GPS +** +** @param [r] port [const char *] serial port +** @param [r] way [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Command_Send_Proximity(const char *port, GPS_PWay *way, int32 n) +{ + int32 ret=0; + + + if(gps_prx_waypt_transfer == -1) + return GPS_UNSUPPORTED; + + + switch(gps_prx_waypt_transfer) + { + case pA400: + ret = GPS_A400_Send(port, way, n); + break; + default: + GPS_Error("Send_Proximity: Unknown proximity protocol"); + break; + } + + return ret; +} + + + +/* @func GPS_Command_Get_Almanac *************************************** +** +** Get almanac from GPS +** +** @param [r] port [const char *] serial port +** @param [w] alm [GPS_PAlmanac **] pointer to almanac array +** +** @return [int32] number of almanac entries +************************************************************************/ + +int32 GPS_Command_Get_Almanac(const char *port, GPS_PAlmanac **alm) +{ + int32 ret=0; + + switch(gps_almanac_transfer) + { + case pA500: + ret = GPS_A500_Get(port,alm); + break; + default: + GPS_Error("Get_Almanac: Unknown almanac protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + +/* @func GPS_Command_Send_Almanac ****************************************** +** +** Send almanac to GPS +** +** @param [r] port [const char *] serial port +** @param [r] alm [GPS_PAlmanac *] almanac array +** @param [r] n [int32] number of almanac entries +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Command_Send_Almanac(const char *port, GPS_PAlmanac *alm, int32 n) +{ + int32 ret=0; + + switch(gps_almanac_transfer) + { + case pA500: + ret = GPS_A500_Send(port, alm, n); + break; + default: + GPS_Error("Send_Almanac: Unknown almanac protocol"); + break; + } + + return ret; +} + + + +/* @func GPS_Command_Get_Time ****************************************** +** +** Get time from GPS +** +** @param [r] port [const char *] serial port +** +** @return [time_t] unix-style time +************************************************************************/ + +time_t GPS_Command_Get_Time(const char *port) +{ + time_t ret=0; + + switch(gps_date_time_transfer) + { + case pA600: + ret = GPS_A600_Get(port); + break; + default: + GPS_Error("Get_Time: Unknown date/time protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + +/* @func GPS_Command_Send_Time ****************************************** +** +** Set GPS time +** +** @param [r] port [const char *] serial port +** @param [r] Time [time_t] unix-style time +** +** @return [int32] true if OK +************************************************************************/ + +int32 GPS_Command_Send_Time(const char *port, time_t Time) +{ + time_t ret=0; + + switch(gps_date_time_transfer) + { + case pA600: + ret = GPS_A600_Send(port, Time); + break; + default: + GPS_Error("Send_Time: Unknown date/time protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + + +/* @func GPS_Command_Get_Position *************************************** +** +** Get position from GPS +** +** @param [r] port [const char *] serial port +** @param [w] lat [double *] latitude (deg) +** @param [w] lon [double *] longitude (deg) +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Command_Get_Position(const char *port, double *lat, double *lon) +{ + int32 ret=0; + + switch(gps_position_transfer) + { + case pA700: + ret = GPS_A700_Get(port,lat,lon); + break; + default: + GPS_Error("Get_Position: Unknown position protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + +/* @func GPS_Command_Send_Position ****************************************** +** +** Set GPS position +** +** @param [r] port [const char *] serial port +** @param [r] lat [double] latitude (deg) +** @param [r] lon [double] longitude (deg) +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Command_Send_Position(const char *port, double lat, double lon) +{ + int32 ret=0; + + switch(gps_position_transfer) + { + case pA700: + ret = GPS_A700_Send(port, lat, lon); + break; + default: + GPS_Error("Send_Position: Unknown position protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + +/* @func GPS_Command_Pvt_On ******************************************** +** +** Instruct GPS to start sending Pvt data every second +** +** @param [r] port [const char *] serial port +** @param [w] fd [int32 *] file descriptor +** +** @return [int32] success if supported and GPS starts sending +************************************************************************/ + +int32 GPS_Command_Pvt_On(const char *port, int32 *fd) +{ + int32 ret=0; + + + if(gps_pvt_transfer == -1) + return GPS_UNSUPPORTED; + + + switch(gps_pvt_transfer) + { + case pA800: + ret = GPS_A800_On(port,fd); + break; + default: + GPS_Error("Pvt_On: Unknown position protocol"); + return PROTOCOL_ERROR; + } + + + return ret; +} + + + +/* @func GPS_Command_Pvt_Off ******************************************** +** +** Instruct GPS to stop sending Pvt data every second +** +** @param [r] port [const char *] serial port +** @param [w] fd [int32 *] file descriptor +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Command_Pvt_Off(const char *port, int32 *fd) +{ + int32 ret=0; + + + if(gps_pvt_transfer == -1) + return GPS_UNSUPPORTED; + + switch(gps_pvt_transfer) + { + case pA800: + ret = GPS_A800_Off(port,fd); + break; + default: + GPS_Error("Pvt_Off: Unknown position protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + +/* @func GPS_Command_Pvt_Get ******************************************** +** +** Get a single PVT info entry +** +** @param [w] fd [int32 *] file descriptor +** @param [w] pvt [GPS_PPvt_Data *] pvt data structure to fill +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Command_Pvt_Get(int32 *fd, GPS_PPvt_Data *pvt) +{ + int32 ret=0; + + if(gps_pvt_transfer == -1) + return GPS_UNSUPPORTED; + + (*pvt)->fix = 0; + + switch(gps_pvt_transfer) + { + case pA800: + ret = GPS_A800_Get(fd,pvt); + break; + default: + GPS_Error("Pvt_Get: Unknown position protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} diff --git a/jeeps/gpscom.h b/jeeps/gpscom.h new file mode 100644 index 000000000..0d8415736 --- /dev/null +++ b/jeeps/gpscom.h @@ -0,0 +1,45 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpscom_h +#define gpscom_h + + +#include "gps.h" +#include + +int32 GPS_Command_Off(const char *port); + +time_t GPS_Command_Get_Time(const char *port); +int32 GPS_Command_Send_Time(const char *port, time_t Time); + +int32 GPS_Command_Get_Position(const char *port, double *lat, double *lon); +int32 GPS_Command_Send_Position(const char *port, double lat, double lon); + +int32 GPS_Command_Pvt_On(const char *port, int32 *fd); +int32 GPS_Command_Pvt_Off(const char *port, int32 *fd); +int32 GPS_Command_Pvt_Get(int32 *fd, GPS_PPvt_Data *pvt); + +int32 GPS_Command_Get_Almanac(const char *port, GPS_PAlmanac **alm); +int32 GPS_Command_Send_Almanac(const char *port, GPS_PAlmanac *alm, int32 n); + +int32 GPS_Command_Get_Track(const char *port, GPS_PTrack **trk); +int32 GPS_Command_Send_Track(const char *port, GPS_PTrack *trk, int32 n); + +int32 GPS_Command_Get_Waypoint(const char *port, GPS_PWay **way,int (*cb)()); +int32 GPS_Command_Send_Waypoint(const char *port, GPS_PWay *way, int32 n, int (*cb)()); + +int32 GPS_Command_Get_Proximity(const char *port, GPS_PWay **way); +int32 GPS_Command_Send_Proximity(const char *port, GPS_PWay *way, int32 n); + +int32 GPS_Command_Get_Route(const char *port, GPS_PWay **way); +int32 GPS_Command_Send_Route(const char *port, GPS_PWay *way, int32 n); + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsdatum.h b/jeeps/gpsdatum.h new file mode 100644 index 000000000..f62405664 --- /dev/null +++ b/jeeps/gpsdatum.h @@ -0,0 +1,206 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsdatum_h +#define gpsdatum_h + + + +typedef struct GPS_SEllipse +{ + char *name; + double a; + double invf; +} GPS_OEllipse, *GPS_PEllipse; + +GPS_OEllipse GPS_Ellipse[]= +{ + { "Airy 1830", 6377563.396, 299.3249646 }, + { "Airy 1830 Modified", 6377340.189, 299.3249646 }, + { "Australian National", 6378160.000, 298.25 }, + { "Bessel 1841 (Namibia)", 6377483.865, 299.1528128 }, + { "Bessel 1841", 6377397.155, 299.1528128 }, + { "Clarke 1866", 6378206.400, 294.9786982 }, + { "Clarke 1880", 6378249.145, 293.465 }, + { "Everest (India 1830)", 6377276.345, 300.8017 }, + { "Everest (Sabah Sarawak)", 6377298.556, 300.8017 }, + { "Everest (India 1956)", 6377301.243, 300.8017 }, + { "Everest (Malaysia 1969)", 6377295.664, 300.8017 }, + { "Everest (Malay & Sing)", 6377304.063, 300.8017 }, + { "Everest (Pakistan)", 6377309.613, 300.8017 }, + { "Modified Fischer 1960", 6378155.000, 298.3 }, + { "Helmert 1906", 6378200.000, 298.3 }, + { "Hough 1960", 6378270.000, 297.0 }, + { "Indonesian 1974", 6378160.000, 298.247 }, + { "International 1924", 6378388.000, 297.0 }, + { "Krassovsky 1940", 6378245.000, 298.3 }, + { "GRS67", 6378160.000, 6356774.516 }, + { "GRS75", 6378140.000, 6356755.288 }, + { "GRS80", 6378137.000, 298.257222101 }, + { "S. American 1969", 6378160.000, 298.25 }, + { "WGS60", 6378165.000, 298.3 }, + { "WGS66", 6378145.000, 298.25 }, + { "WGS72", 6378135.000, 298.26 }, + { "WGS84", 6378137.000, 298.257223563 } +}; + + + +typedef struct GPS_SDatum +{ + char *name; + int ellipse; + double dx; + double dy; + double dz; +} GPS_ODatum, *GPS_PDatum; + +GPS_ODatum GPS_Datum[]= +{ +/* 000 */ { "Adindan", 6, -166, -15, 204 }, +/* 001 */ { "AFG", 18, -43, -163, 45 }, +/* 002 */ { "Ain-El-Abd", 17, -150, -251, -2 }, +/* 003 */ { "Alaska-NAD27", 5, -5, 135, 172 }, +/* 004 */ { "Alaska-Canada", 6, -9, 151, 185 }, +/* 005 */ { "Anna-1-Astro", 2, -491, -22, 435 }, +/* 006 */ { "ARC 1950 Mean", 6, -143, -90, -294 }, +/* 007 */ { "ARC 1960 Mean", 6, -160, -8, -300 }, +/* 008 */ { "Asc Island 58", 17, -207, 107, 52 }, +/* 009 */ { "Astro B4", 17, 114, -116, -333 }, +/* 010 */ { "Astro Beacon E", 17, 145, 75, -272 }, +/* 011 */ { "Astro pos 71/4", 17, -320, 550, -494 }, +/* 012 */ { "Astro stn 52", 17, 124, -234, -25 }, +/* 013 */ { "Australia Geo 1984", 2, -134, -48, 149 }, +/* 014 */ { "Bahamas NAD27", 6, -4, 154, 178 }, +/* 015 */ { "Bellevue IGN", 17, -127, -769, 472 }, +/* 016 */ { "Bermuda 1957", 6, -73, 213, 296 }, +/* 017 */ { "Bukit Rimpah", 4, -384, 664, -48 }, +/* 018 */ { "Camp_Area_Astro", 17, -104, -129, 239 }, +/* 019 */ { "Campo_Inchauspe", 17, -148, 136, 90 }, +/* 020 */ { "Canada_Mean(NAD27)", 5, -10, 158, 187 }, +/* 021 */ { "Canal_Zone_(NAD27)", 5, 0, 125, 201 }, +/* 022 */ { "Canton_Island_1966", 17, 298, -304, -375 }, +/* 023 */ { "Cape", 6, -136, -108, -292 }, +/* 024 */ { "Cape_Canaveral_mean", 5, -2, 150, 181 }, +/* 025 */ { "Carribean NAD27", 5, -7, 152, 178 }, +/* 026 */ { "Carthage", 6, -263, 6, 431 }, +/* 027 */ { "Cent America NAD27", 5 , 0, 125, 194 }, +/* 028 */ { "Chatham 1971", 17, 175, -38, 113 }, +/* 029 */ { "Chua Astro", 17, -134, 229, -29 }, +/* 030 */ { "Corrego Alegre", 17, -206, 172, -6 }, +/* 031 */ { "Cuba NAD27", 5, -9, 152, 178 }, +/* 032 */ { "Cyprus", 17, -104, -101, -140 }, +/* 033 */ { "Djakarta(Batavia)", 4, -377, 681, -50 }, +/* 034 */ { "DOS 1968", 17, 230, -199, -752 }, +/* 035 */ { "Easter lsland 1967", 17, 211, 147, 111 }, +/* 036 */ { "Egypt", 17, -130, -117, -151 }, +/* 037 */ { "European 1950", 17, -87, -96, -120 }, +/* 038 */ { "European 1950 mean", 17, -87, -98, -121 }, +/* 039 */ { "European 1979 mean", 17, -86, -98, -119 }, +/* 040 */ { "Finnish Nautical", 17, -78, -231, -97 }, +/* 041 */ { "Gandajika Base", 17, -133, -321, 50 }, +/* 042 */ { "Geodetic Datum 49", 17, 84, -22, 209 }, +/* 043 */ { "Ghana", 26, 0, 0, 0 }, +/* 044 */ { "Greenland NAD27", 5, 11, 114, 195 }, +/* 045 */ { "Guam 1963", 5, -100, -248, 259 }, +/* 046 */ { "Gunung Segara", 4, -403, 684, 41 }, +/* 047 */ { "Gunung Serindung 1962", 26, 0, 0, 0 }, +/* 048 */ { "GUX1 Astro", 17, 252, -209, -751 }, +/* 049 */ { "Herat North", 17, -333, -222, 114 }, +/* 050 */ { "Hjorsey 1955", 17, -73, 46, 86 }, +/* 051 */ { "Hong Kong 1963", 17, -156, -271, -189 }, +/* 052 */ { "Hu-Tzu-Shan", 17, -634, -549, -201 }, +/* 053 */ { "Indian", 9, 289, 734, 257 }, +/* 054 */ { "Iran", 17, -117, -132, -164 }, +/* 055 */ { "Ireland 1965", 1, 506, -122, 611 }, +/* 056 */ { "ISTS 073 Astro 69", 17, 208, -435, -229 }, +/* 057 */ { "Johnston Island 61", 17, 191, -77, -204 }, +/* 058 */ { "Kandawala", 7, -97, 787, 86 }, +/* 059 */ { "Kerguelen Island", 17, 145, -187, 103 }, +/* 060 */ { "Kertau 48", 11, -11, 851, 5 }, +/* 061 */ { "L.C. 5 Astro", 5, 42, 124, 147 }, +/* 062 */ { "La Reunion", 17, 94, -948, -1262 }, +/* 063 */ { "Liberia 1964", 6, -90, 40, 88 }, +/* 064 */ { "Luzon", 5, -133, -77, -51 }, +/* 065 */ { "Mahe 1971", 6, 41, -220, -134 }, +/* 066 */ { "Marco Astro", 17, -289, -124, 60 }, +/* 067 */ { "Masirah Is. Nahrwan", 6, -247, -148, 369 }, +/* 068 */ { "Massawa", 4, 639, 405, 60 }, +/* 069 */ { "Merchich", 6, 31, 146, 47 }, +/* 070 */ { "Mexico NAD27", 5, -12, 130, 190 }, +/* 071 */ { "Midway Astro 61", 17, 912, -58, 1227 }, +/* 072 */ { "Mindanao", 5, -133, -79, -72 }, +/* 073 */ { "Minna", 6, -92, -93, 122 }, +/* 074 */ { "Montjong Lowe", 26, 0, 0, 0 }, +/* 075 */ { "Nahrwan", 6, -231, -196, 482 }, +/* 076 */ { "Naparima BWI", 17, -2, 374, 172 }, +/* 077 */ { "North America 83", 21, 0, 0, 0 }, +/* 078 */ { "N. America 1927 mean", 5, -8, 160, 176 }, +/* 079 */ { "Observatorio 1966", 17, -425, -169, 81 }, +/* 080 */ { "Old Egyptian", 14, -130, 110, -13 }, +/* 081 */ { "Old Hawaiian_mean", 5, 89, -279, -183 }, +/* 082 */ { "Old Hawaiian Kauai", 5, 45, -290, -172 }, +/* 083 */ { "Old Hawaiian Maui", 5, 65, -290, -190 }, +/* 084 */ { "Old Hawaiian Oahu", 5, 56, -284, -181 }, +/* 085 */ { "Oman", 6, -346, -1, 224 }, +/* 086 */ { "OSGB36", 0, 375, -111, 431 }, +/* 087 */ { "Pico De Las Nieves", 17, -307, -92, 127 }, +/* 088 */ { "Pitcairn Astro 67", 17, 185, 165, 42 }, +/* 089 */ { "S. Am. 1956 mean(P)", 17, -288, 175, -376 }, +/* 090 */ { "S. Chilean 1963 (P)", 17, 16, 196, 93 }, +/* 091 */ { "Puerto Rico", 5, 11, 72, -101 }, +/* 092 */ { "Pulkovo 1942", 18, 28, -130, -95 }, +/* 093 */ { "Qornoq", 17, 164, 138, -189 }, +/* 094 */ { "Quatar National", 17, -128, -283, 22 }, +/* 095 */ { "Rome 1940", 17, -225, -65, 9 }, +/* 096 */ { "S-42(Pulkovo1942)", 18, 28, -121, -77 }, +/* 097 */ { "S.E.Asia_(Indian)", 7, 173, 750, 264 }, +/* 098 */ { "SAD-69/Brazil", 22, -60, -2, -41 }, +/* 099 */ { "Santa Braz", 17, -203, 141, 53 }, +/* 100 */ { "Santo (DOS)", 17, 170, 42, 84 }, +/* 101 */ { "Sapper Hill 43", 17, -355, 16, 74 }, +/* 102 */ { "Schwarzeck", 3, 616, 97, -251 }, +/* 103 */ { "Sicily", 17, -97, -88, -135 }, +/* 104 */ { "Sierra Leone 1960", 26, 0, 0, 0 }, +/* 105 */ { "S. Am. 1969 mean", 22, -57, 1, -41 }, +/* 106 */ { "South Asia", 13, 7, -10, -26 }, +/* 107 */ { "Southeast Base", 17, -499, -249, 314 }, +/* 108 */ { "Southwest Base", 17, -104, 167, -38 }, +/* 109 */ { "Tananarive Obs 25", 17, -189, -242, -91 }, +/* 110 */ { "Thai/Viet (Indian)", 7, 214, 836, 303 }, +/* 111 */ { "Timbalai 1948", 7, -689, 691, -45 }, +/* 112 */ { "Tokyo mean", 4, -128, 481, 664 }, +/* 113 */ { "Tristan Astro 1968", 17, -632, 438, -609 }, +/* 114 */ { "Unites Arab Emirates", 6, -249, -156, 381 }, +/* 115 */ { "Viti Levu 1916", 6, 51, 391, -36 }, +/* 116 */ { "Wake Eniwetok 60", 15, 101, 52, -39 }, +/* 117 */ { "WGS 72", 25, 0, 0, 5 }, +/* 118 */ { "WGS 84", 26, 0, 0, 0 }, +/* 119 */ { "Yacare", 17, -155, 171, 37 }, +/* 120 */ { "Zanderij", 17, -265, 120, -358 }, +/* 121 */ { "Sweden", 4, 424.3, -80.5, 613.1 }, + { NULL, 0, 0, 0, 0 } +}; + + +/* UK Ordnance Survey Nation Grid Map Codes */ +static char *UKNG[]= +{ + "SV","SW","SX","SY","SZ","TV","TW","SQ","SR","SS","ST","SU","TQ","TR", + "SL","SM","SN","SO","SP","TL","TM","SF","SG","SH","SJ","SK","TF","TG", + "SA","SB","SC","SD","SE","TA","TB","NV","NW","NX","NY","NZ","OV","OW", + "NQ","NR","NS","NT","NU","OQ","OR","NL","NM","NN","NO","NP","OL","OM", + "NF","NG","NH","NJ","NK","OF","OG","NA","NB","NC","ND","NE","OA","OB", + "HV","HW","HX","HY","HZ","JV","JW","HQ","HR","HS","HT","HU","JQ","JR", + "HL","HM","HN","HO","HP","JL","JM","" +}; + + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsfmt.c b/jeeps/gpsfmt.c new file mode 100644 index 000000000..f4919a092 --- /dev/null +++ b/jeeps/gpsfmt.c @@ -0,0 +1,1562 @@ +/******************************************************************** +** @source JEEPS output functions +** +** @author Copyright (C) 1999 Alan Bleasby +** @version 1.0 +** @modified Dec 28 1999 Alan Bleasby. First version +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include +#include + + +static void GPS_Fmt_Print_Way100(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way101(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way102(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way103(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way104(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way105(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way106(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way107(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way108(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way109(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way150(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way151(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way152(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way154(GPS_PWay way, FILE *outf); +static void GPS_Fmt_Print_Way155(GPS_PWay way, FILE *outf); + +static void GPS_Fmt_Print_Track301(GPS_PTrack *trk, int32 n, FILE *outf); +static void GPS_Fmt_Print_D300(GPS_PTrack trk, FILE *outf); +static void GPS_Fmt_Print_D301(GPS_PTrack trk, FILE *outf); + +static int32 GPS_Fmt_Print_Route201(GPS_PWay *way, int32 n, FILE *outf); + + +char *gps_marine_sym[]= +{ + "Anchor","Bell","Diamond-grn","Diamond_red","Dive1","Dive2","Dollar", + "Fish","Fuel","Horn","House","Knife","Light","Mug","Skull", + "Square_grn","Square_red","Wbuoy","Wpt_dot","Wreck","Null","Mob", + + "Buoy_amber","Buoy_blck","Buoy_blue","Buoy_grn","Buoy_grn_red", + "Buoy_grn_wht","Buoy_orng","Buoy_red","Buoy_red_grn","Buoy_red_wht", + "Buoy_violet","Buoy_wht","Buoy_wht_grn","Buoy_wht_red","Dot","Rbcn", + + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","", + + "Boat_ramp","Camp","Toilets","Showers","Drinking_wtr","Phone", + "1st_aid","Info","Parking","Park","Picnic","Scenic","Skiing", + "Swimming","Dam","Controlled","Danger","Restricted","Null_2","Ball", + "Car","Deer","Shpng_trolley","Lodging","Mine","Trail_head", + "Lorry_stop","User_exit","Flag","Circle-x" +}; + + + +char *gps_land_sym[]= +{ + "Is_hwy","Us_hwy","St_hwy","Mi_mrkr","Trcbck","Golf","Sml_cty", + "Med_cty","Lrg_cty","Freeway","Ntl_hwy","Cap_cty","Amuse_pk", + "Bowling","Car_rental","Car_repair","Fastfood","Fitness","Film", + "Museum","Chemist","Pizza","Post_ofc","Rv_park","School", + "Stadium","Shop","Zoo","Petrol_plus","Theatre","Ramp_int", + "St_int","","","Weigh_stn","Toll_booth","Elev_pt","Ex_no_srvc", + "Geo_place_mm","Geo_place_wtr","Geo_place_lnd","Bridge","Building", + "Cemetery","Church","Civil_loc","Crossing","Hist_town","River_Embankment", + "Military_loc","Oil_field","Tunnel","Beach","Forest","Summit", + "Lrg_ramp_int","Lrg_exit_no_srvc","Official_badge","Gambling", + "Snow_ski","Ice_ski","Tow_truck","Border" +}; + + +char *gps_aviation_sym[]= +{ + "Airport","Int","Ndb","Vor","Heliport","Private","Soft_fld", + "Tall_tower","Short_tower","Glider","Ultralight","Parachute", + "Vortac","Vordme","Faf","Lom","Map","Tacan","Seaplane" +}; + + +char *gps_16_sym[]= +{ + "Dot","House","Fuel","Car","Fish","Boat","Anchor","Wreck", + "Exit","Skull","Flag","Camp","Circle-x","Deer","1st_aid","Back_track" +}; + + + + + +/* @func GPS_Fmt_Print_Time ******************************************** +** +** Output Date/time +** +** @param [r] Time [time_t] unix-style time +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +void GPS_Fmt_Print_Time(time_t Time, FILE *outf) +{ + (void) fprintf(outf,"%s",ctime(&Time)); + fflush(outf); + + return; +} + + + +/* @func GPS_Fmt_Print_Position ******************************************** +** +** Output position +** +** @param [r] lat [double] latitude (deg) +** @param [r] lon [double] longitude (deg) +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +void GPS_Fmt_Print_Position(double lat, double lon, FILE *outf) +{ + (void) fprintf(outf,"Latitude: %f Longitude %f\n",lat,lon); + fflush(outf); + + return; +} + + + +/* @func GPS_Fmt_Print_Pvt ******************************************** +** +** Output pvt +** +** @param [r] pvt [GPS_PPvt_Data] pvt +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +void GPS_Fmt_Print_Pvt(GPS_PPvt_Data pvt, FILE *outf) +{ + + (void) fprintf(outf,"Fix: "); + switch(pvt->fix) + { + case 0: + (void) fprintf(outf,"UNUSABLE\n\n"); + break; + case 1: + (void) fprintf(outf,"INVALID \n\n"); + break; + case 2: + (void) fprintf(outf,"2D \n\n"); + break; + case 3: + (void) fprintf(outf,"3D \n\n"); + break; + case 4: + (void) fprintf(outf,"2D-diff \n\n"); + break; + case 5: + (void) fprintf(outf,"2D-diff \n\n"); + break; + default: + (void) fprintf(stderr,"PVT: Unsupported Fix type\n"); + break; + } + + (void) fprintf(outf,"Altitude (WGS 84): %-20f \n",pvt->alt); + (void) fprintf(outf,"EPE: %-20f \n",pvt->epe); + (void) fprintf(outf,"EPE (hor only): %-20f \n",pvt->eph); + (void) fprintf(outf,"EPE (ver only): %-20f \n",pvt->epv); + (void) fprintf(outf,"Time of week: %-20d \n",(int)pvt->tow); + (void) fprintf(outf,"Latitude: %-20f \n",pvt->lat); + (void) fprintf(outf,"Longitude: %-20f \n",pvt->lon); + (void) fprintf(outf,"East velocity: %-20f \n",pvt->east); + (void) fprintf(outf,"North velocity: %-20f \n",pvt->north); + (void) fprintf(outf,"Upward velocity %-20f \n",pvt->up); + (void) fprintf(outf,"Height above MSL: %-20f \n",pvt->msl_hght+pvt->alt); + (void) fprintf(outf,"Leap seconds: %-20d \n",pvt->leap_scnds); + (void) fprintf(outf,"Week number days: %-20d \n",(int)pvt->wn_days); + + fflush(outf); + + return; +} + + + +/* @func GPS_Fmt_Print_Almanac ******************************************** +** +** Output almanac +** +** @param [r] alm [GPS_PAlmanac *] almanac array +** @param [r] n [int32] number of almanac entries +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +void GPS_Fmt_Print_Almanac(GPS_PAlmanac *alm, int32 n, FILE *outf) +{ + int32 i; + int32 t; + int32 s; + + /* Type 0 models require all 32 satellites to be sent */ + t=32; + s=0; + if(n && alm[0]->svid!=0xff) + { + s=1; + t=n; + } + (void) fprintf(outf,"Almanac %d %d\n",(int)t,(int)s); + + + for(i=0;iwn<0) continue; + + if(alm[i]->svid == 0xff) + alm[i]->svid = i; + (void) fprintf(outf,"#\n#\n"); + (void) fprintf(outf,"\tID: %d\n", + alm[i]->svid+1); + (void) fprintf(outf,"\tWeek number: %d\n", + alm[i]->wn); + (void) fprintf(outf,"\tAlmanac Data Reference Time: %f\n", + alm[i]->toa); + (void) fprintf(outf,"\tClock Correction Coeff (s): %f\n", + alm[i]->af0); + (void) fprintf(outf,"\tClock Correction Coeff (s/s): %f\n", + alm[i]->af1); + (void) fprintf(outf,"\tEccentricity: %f\n", + alm[i]->e); + (void) fprintf(outf,"\tSqrt of semi-major axis: %f\n", + alm[i]->sqrta); + (void) fprintf(outf,"\tMean Anomaly at Ref. Time: %f\n", + alm[i]->m0); + (void) fprintf(outf,"\tArgument of perigee: %f\n", + alm[i]->w); + (void) fprintf(outf,"\tRight ascension: %f\n", + alm[i]->omg0); + (void) fprintf(outf,"\tRate of right ascension: %f\n", + alm[i]->odot); + (void) fprintf(outf,"\tInclination angle: %f\n", + alm[i]->i); + (void) fprintf(outf,"\tHealth: %d\n", + alm[i]->hlth); + } + + + fflush(outf); + + return; +} + + + +/* @func GPS_Fmt_Print_Track ******************************************** +** +** Output track log +** +** @param [r] trk [GPS_PTrack *] track array +** @param [r] n [int32] number of track entries +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +void GPS_Fmt_Print_Track(GPS_PTrack *trk, int32 n, FILE *outf) +{ + int32 i; + + + switch(gps_trk_transfer) + { + case pA300: + break; + case pA301: + GPS_Fmt_Print_Track301(trk,n,outf); + return; + default: + GPS_Error("GPS_Fmt_Print_Track: Unknown protocol"); + return; + } + + + (void) fprintf(outf,"Track log 300 %d\n#\n",(int)gps_trk_type); + (void) fprintf(outf,"Start\n#\n"); + + for(i=0;itnew) + (void) fprintf(outf,"#\nNew track\n#\n"); + + switch(gps_trk_type) + { + case pD300: + GPS_Fmt_Print_D300(trk[i],outf); + break; + case pD301: + GPS_Fmt_Print_D301(trk[i],outf); + break; + default: + break; + } + } + + (void) fprintf(outf,"End\n#\n"); + fflush(outf); + + return; +} + + + +/* @funcstatic GPS_Fmt_Print_Track301 *********************************** +** +** Output track log +** +** @param [r] trk [GPS_PTrack *] track array +** @param [r] n [int32] number of track entries +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Track301(GPS_PTrack *trk, int32 n, FILE *outf) +{ + int32 i; + + if(!n) + return; + + (void) fprintf(outf,"Track log 301 %d\n#\n",(int)gps_trk_type); + (void) fprintf(outf,"Start\n#\n"); + + for(i=0;iishdr) + { + (void) fprintf(outf,"Header\n"); + (void) fprintf(outf,"\tIdent: %s\n",trk[i]->trk_ident); + (void) fprintf(outf,"\tDisplay: %d\n",(int)trk[i]->dspl); + (void) fprintf(outf,"\tColour: %d\n#\n", + (int)trk[i]->colour); + continue; + } + + if(trk[i]->tnew) + (void) fprintf(outf,"#\nNew track\n#\n"); + + switch(gps_trk_type) + { + case pD300: + GPS_Fmt_Print_D300(trk[i],outf); + break; + case pD301: + GPS_Fmt_Print_D301(trk[i],outf); + break; + default: + break; + } + } + + (void) fprintf(outf,"End\n#\n"); + fflush(outf); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_D300 **************************************** +** +** Output track log +** +** @param [r] trk [GPS_PTrack *] track array +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_D300(GPS_PTrack trk, FILE *outf) +{ + (void) fprintf(outf,"\tLatitude: %f\n",trk->lat); + (void) fprintf(outf,"\tLongitude: %f\n",trk->lon); + if(trk->Time) + (void) fprintf(outf,"\tTime: %s\n",ctime(&trk->Time)); + else + (void) fprintf(outf,"\tTime: Computer\n\n"); + + return; +} + + + +/* @funcstatic GPS_Fmt_Print_D301 **************************************** +** +** Output track log +** +** @param [r] trk [GPS_PTrack *] track array +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_D301(GPS_PTrack trk, FILE *outf) +{ + (void) fprintf(outf,"\tLatitude: %f\n",trk->lat); + (void) fprintf(outf,"\tLongitude: %f\n",trk->lon); + if(trk->Time) + (void) fprintf(outf,"\tTime: %s",ctime(&trk->Time)); + else + (void) fprintf(outf,"\tTime: Computer\n"); + (void) fprintf(outf,"\tAltitude: %f\n",trk->alt); + (void) fprintf(outf,"\tDepth: %f\n\n",trk->dpth); + + return; +} + + + + +/* @func GPS_Fmt_Print_Waypoint ***************************************** +** +** Output waypoints +** +** @param [r] way [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** @param [w] outf [FILE *] output stream +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Fmt_Print_Waypoint(GPS_PWay *way, int32 n, FILE *outf) +{ + int32 i; + + + if(!n) + return 1; + + (void) fprintf(outf,"Waypoints Type: %d\n#\nStart\n#\n", + (int)way[0]->prot); + + + for(i=0;iprot) + { + case 100: + GPS_Fmt_Print_Way100(way[i],outf); + break; + case 101: + GPS_Fmt_Print_Way101(way[i],outf); + break; + case 102: + GPS_Fmt_Print_Way102(way[i],outf); + break; + case 103: + GPS_Fmt_Print_Way103(way[i],outf); + break; + case 104: + GPS_Fmt_Print_Way104(way[i],outf); + break; + case 105: + GPS_Fmt_Print_Way105(way[i],outf); + break; + case 106: + GPS_Fmt_Print_Way106(way[i],outf); + break; + case 107: + GPS_Fmt_Print_Way107(way[i],outf); + break; + case 108: + GPS_Fmt_Print_Way108(way[i],outf); + break; + case 109: + GPS_Fmt_Print_Way109(way[i],outf); + break; + case 150: + GPS_Fmt_Print_Way150(way[i],outf); + break; + case 151: + GPS_Fmt_Print_Way151(way[i],outf); + break; + case 152: + GPS_Fmt_Print_Way152(way[i],outf); + break; + case 154: + GPS_Fmt_Print_Way154(way[i],outf); + break; + case 155: + GPS_Fmt_Print_Way155(way[i],outf); + break; + default: + GPS_Error("Print_Waypoint: Unknown waypoint protocol"); + return PROTOCOL_ERROR; + } + (void) fprintf(outf,"#\n"); + } + (void) fprintf(outf,"End\n#\n"); + + return 1; +} + + + +/* @func GPS_Fmt_Print_Proximity ***************************************** +** +** Output proximity +** +** @param [r] way [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** @param [w] outf [FILE *] output stream +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Fmt_Print_Proximity(GPS_PWay *way, int32 n, FILE *outf) +{ + int32 i; + + + if(!n) + return 1; + + (void) fprintf(outf,"Waypoints Type: %d\n#\nStart\n#\n", + (int)way[0]->prot); + + + for(i=0;iprot) + { + case 400: + GPS_Fmt_Print_Way100(way[i],outf); + break; + case 101: + GPS_Fmt_Print_Way101(way[i],outf); + break; + case 102: + GPS_Fmt_Print_Way102(way[i],outf); + break; + case 403: + GPS_Fmt_Print_Way103(way[i],outf); + break; + case 104: + GPS_Fmt_Print_Way104(way[i],outf); + break; + case 105: + GPS_Fmt_Print_Way105(way[i],outf); + break; + case 106: + GPS_Fmt_Print_Way106(way[i],outf); + break; + case 107: + GPS_Fmt_Print_Way107(way[i],outf); + break; + case 108: + GPS_Fmt_Print_Way108(way[i],outf); + break; + case 109: + GPS_Fmt_Print_Way109(way[i],outf); + break; + case 450: + GPS_Fmt_Print_Way150(way[i],outf); + (void) fprintf(outf,"\tPindex: %d\n",(int)way[i]->idx); + break; + case 151: + GPS_Fmt_Print_Way151(way[i],outf); + break; + case 152: + GPS_Fmt_Print_Way152(way[i],outf); + break; + case 154: + GPS_Fmt_Print_Way154(way[i],outf); + break; + case 155: + GPS_Fmt_Print_Way155(way[i],outf); + break; + default: + GPS_Error("Print_Proximity: Unknown proximity protocol"); + return PROTOCOL_ERROR; + } + (void) fprintf(outf,"\tDistance: %f\n",way[i]->dst); + (void) fprintf(outf,"#\n"); + } + (void) fprintf(outf,"End\n#\n"); + + return 1; +} + + + + +/* @funcstatic GPS_Fmt_Print_Way100 ************************************* +** +** Output waypoint D100 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way100(GPS_PWay way, FILE *outf) +{ + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_Way101 ************************************ +** +** Output waypoint D101 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way101(GPS_PWay way, FILE *outf) +{ + + if(way->smbl > 176) way->smbl=36; + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + (void) fprintf(outf,"\tSymbol: %d [%s]\n",(int)way->smbl, + gps_marine_sym[way->smbl]); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_Way102 ************************************* +** +** Output waypoint D102 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way102(GPS_PWay way, FILE *outf) +{ + char **p; + int32 x; + + if(way->smbl < 8192) + { + p = gps_marine_sym; + x = 0; + } + else if(way->smbl < 16384) + { + p = gps_land_sym; + x = 8192; + } + else + { + p = gps_aviation_sym; + x = 16384; + } + + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + (void) fprintf(outf,"\tSymbol: %d [%s]\n",(int)way->smbl, + p[way->smbl-x]); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_Way103 ************************************ +** +** Output waypoint D103 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way103(GPS_PWay way, FILE *outf) +{ + static char *dspl[]= + { + "SW","S","SC" + }; + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + (void) fprintf(outf,"\tSymbol: %-6d [%s]\n",(int)way->smbl, + gps_16_sym[way->smbl]); + (void) fprintf(outf,"\tDisplay: %-6d [%s]\n",(int)way->dspl, + dspl[way->dspl]); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_Way104 ************************************* +** +** Output waypoint D104 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way104(GPS_PWay way, FILE *outf) +{ + static char *dspl[]= + { + "S","S","","SW","","SC" + }; + char **p; + int32 x; + + if(way->smbl < 8192) + { + p = gps_marine_sym; + x = 0; + } + else if(way->smbl < 16384) + { + p = gps_land_sym; + x = 8192; + } + else + { + p = gps_aviation_sym; + x = 16384; + } + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + (void) fprintf(outf,"\tSymbol: %-6d [%s]\n",(int)way->smbl, + p[way->smbl-x]); + (void) fprintf(outf,"\tDisplay: %-6d [%s]\n",(int)way->dspl, + dspl[way->dspl]); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_Way105 ************************************ +** +** Output waypoint D105 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way105(GPS_PWay way, FILE *outf) +{ + char **p; + int32 x; + + if(way->smbl < 8192) + { + p = gps_marine_sym; + x = 0; + } + else if(way->smbl < 16384) + { + p = gps_land_sym; + x = 8192; + } + else + { + p = gps_aviation_sym; + x = 16384; + } + + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tSymbol: %-6d [%s]\n",(int)way->smbl, + p[way->smbl-x]); + (void) fprintf(outf,"\tWpt_ident %s\n",way->wpt_ident); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_Way106 ************************************* +** +** Output waypoint D106 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way106(GPS_PWay way, FILE *outf) +{ + char **p; + int32 x; + + if(way->smbl < 8192) + { + p = gps_marine_sym; + x = 0; + } + else if(way->smbl < 16384) + { + p = gps_land_sym; + x = 8192; + } + else + { + p = gps_aviation_sym; + x = 16384; + } + + if(!way->wpt_class) + { + (void) fprintf(outf,"\tClass: %d [User]\n",way->wpt_class); + (void) fprintf(outf,"\tSubclass: %d [%-13.13s]\n", + way->wpt_class,way->subclass); + (void) fprintf(outf,"\tSubclass:\n"); + } + else + { + (void) fprintf(outf,"\tClass: %d [Non-user]\n", + way->wpt_class); + (void) fprintf(outf,"\tSubclass: %d [%13.13s]\n", + way->wpt_class, + way->subclass); + } + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tSymbol: %-6d [%s]\n",(int)way->smbl, + p[way->smbl-x]); + (void) fprintf(outf,"\tWpt_ident %s\n",way->wpt_ident); + (void) fprintf(outf,"\tLnk_ident %s\n",way->lnk_ident); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_Way107 ************************************ +** +** Output waypoint D107 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way107(GPS_PWay way, FILE *outf) +{ + static char *dspl[]= + { + "SW","S","SC" + }; + static char *col[]= + { + "Default","Red","Green","Blue" + }; + + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + (void) fprintf(outf,"\tSymbol: %-6d [%s]\n",(int)way->smbl, + gps_16_sym[way->smbl]); + (void) fprintf(outf,"\tDisplay: %-6d [%s]\n",(int)way->dspl, + dspl[way->dspl]); + (void) fprintf(outf,"\tColour: %-6d [%s]\n",(int)way->colour, + col[way->colour]); + + return; +} + + + +/* @funcstatic GPS_Fmt_Print_Way108 ************************************ +** +** Output waypoint D108 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way108(GPS_PWay way, FILE *outf) +{ + char **p; + int32 x; + + static char *dspl[]= + { + "SW","S","SC" + }; + + static char *col[]= + { + "Black","Dark_Red","Dark_Green","Dark_Yellow","Dark_Blue", + "Dark_Magenta","Dark_Cyan","Light_Grey","Dark_Grey","Red","Green", + "Yellow","Blue","Magenta","Cyan","White" + }; + + + if(way->smbl < 8192) + { + p = gps_marine_sym; + x = 0; + } + else if(way->smbl < 16384) + { + p = gps_land_sym; + x = 8192; + } + else + { + p = gps_aviation_sym; + x = 16384; + } + + (void) fprintf(outf,"\tIdent: %s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + if(way->colour==0xff) + (void) fprintf(outf,"\tColour: 255 [Default]\n"); + else + (void) fprintf(outf,"\tColour: %-6d [%s]\n",(int)way->colour, + col[way->colour]); + (void) fprintf(outf,"\tDisplay: %-6d [%s]\n",(int)way->dspl, + dspl[way->dspl]); + (void) fprintf(outf,"\tSymbol: %-6d [%s]\n",(int)way->smbl, + p[way->smbl-x]); + (void) fprintf(outf,"\tAltitude: %d\n",(int)way->alt); + (void) fprintf(outf,"\tDepth: %f\n",way->dpth); + (void) fprintf(outf,"\tState: %-2.2s\n",way->state); + (void) fprintf(outf,"\tCountry: %-2.2s\n",way->cc); + (void) fprintf(outf,"\tClass: %d\n",way->wpt_class); + if(way->wpt_class>=0x80 && way->wpt_class<=0x85) + (void) fprintf(outf,"\tSubclass: %18.18s\n",way->subclass); + if(!way->wpt_class) + (void) fprintf(outf,"\tComment: %s\n",way->cmnt); + if(way->wpt_class>=0x40 && way->wpt_class<=0x46) + { + (void) fprintf(outf,"\tFacility: %s\n",way->facility); + (void) fprintf(outf,"\tCity: %s\n",way->city); + } + if(way->wpt_class==0x83) + (void) fprintf(outf,"\tAddress: %s\n",way->addr); + if(way->wpt_class==0x82) + (void) fprintf(outf,"\tCross Road: %s\n",way->cross_road); + + + return; +} + +/* @funcstatic GPS_Fmt_Print_Way109 ************************************ +** +** Output waypoint D109 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way109(GPS_PWay way, FILE *outf) +{ + char **p; + int32 x; + + static char *dspl[]= + { + "SW","S","SC" + }; + + static char *col[]= + { + "Black","Dark_Red","Dark_Green","Dark_Yellow","Dark_Blue", + "Dark_Magenta","Dark_Cyan","Light_Grey","Dark_Grey","Red","Green", + "Yellow","Blue","Magenta","Cyan","White" + }; + + + if(way->smbl < 8192) + { + p = gps_marine_sym; + x = 0; + } + else if(way->smbl < 16384) + { + p = gps_land_sym; + x = 8192; + } + else + { + p = gps_aviation_sym; + x = 16384; + } + + (void) fprintf(outf,"\tIdent: %s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + if(way->colour==0xff) + (void) fprintf(outf,"\tColour: 255 [Default]\n"); + else + (void) fprintf(outf,"\tColour: %-6d [%s]\n",(int)way->colour, + col[way->colour]); +#if 0 + /* avoid bounds violation in D109. Probably masking a bug elswhere...*/ + (void) fprintf(outf,"\tDisplay: %-6d [%s]\n",(int)way->dspl, + dspl[way->dspl]); +#endif + (void) fprintf(outf,"\tSymbol: %-6d [%s]\n",(int)way->smbl, + p[way->smbl-x]); + (void) fprintf(outf,"\tAltitude: %d\n",(int)way->alt); + (void) fprintf(outf,"\tDepth: %f\n",way->dpth); + (void) fprintf(outf,"\tState: %-2.2s\n",way->state); + (void) fprintf(outf,"\tCountry: %-2.2s\n",way->cc); + (void) fprintf(outf,"\tClass: %d\n",way->wpt_class); + if(way->wpt_class>=0x80 && way->wpt_class<=0x85) + (void) fprintf(outf,"\tSubclass: %18.18s\n",way->subclass); + if(!way->wpt_class) + (void) fprintf(outf,"\tComment: %s\n",way->cmnt); + if(way->wpt_class>=0x40 && way->wpt_class<=0x46) + { + (void) fprintf(outf,"\tFacility: %s\n",way->facility); + (void) fprintf(outf,"\tCity: %s\n",way->city); + } + if(way->wpt_class==0x83) + (void) fprintf(outf,"\tAddress: %s\n",way->addr); + if(way->wpt_class==0x82) + (void) fprintf(outf,"\tCross Road: %s\n",way->cross_road); + + + return; +} + +/* @funcstatic GPS_Fmt_Print_Way150 ************************************* +** +** Output waypoint D150 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way150(GPS_PWay way, FILE *outf) +{ + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + (void) fprintf(outf,"\tClass: %d\n",way->wpt_class); + if(way->wpt_class!=4) + { + (void) fprintf(outf,"\tCountry: %-2.2s\n",way->cc); + (void) fprintf(outf,"\tCity: %-24.24s\n",way->city); + (void) fprintf(outf,"\tState: %-2.2s\n",way->state); + (void) fprintf(outf,"\tName: %-30.30s\n",way->name); + } + if(!way->wpt_class) + (void) fprintf(outf,"\tAltitude: %d\n",(int)way->alt); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_Way151 ************************************ +** +** Output waypoint D151 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way151(GPS_PWay way, FILE *outf) +{ + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + (void) fprintf(outf,"\tClass: %d\n",way->wpt_class); + if(way->wpt_class!=2) + { + (void) fprintf(outf,"\tCountry: %-2.2s\n",way->cc); + (void) fprintf(outf,"\tCity: %-24.24s\n",way->city); + (void) fprintf(outf,"\tState: %-2.2s\n",way->state); + (void) fprintf(outf,"\tName: %-30.30s\n",way->name); + } + if(!way->wpt_class) + (void) fprintf(outf,"\tAltitude: %d\n",(int)way->alt); + + return; +} + + + +/* @funcstatic GPS_Fmt_Print_Way152 ************************************ +** +** Output waypoint D152 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way152(GPS_PWay way, FILE *outf) +{ + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + (void) fprintf(outf,"\tClass: %d\n",way->wpt_class); + if(way->wpt_class!=4) + { + (void) fprintf(outf,"\tCountry: %-2.2s\n",way->cc); + (void) fprintf(outf,"\tCity: %-24.24s\n",way->city); + (void) fprintf(outf,"\tState: %-2.2s\n",way->state); + (void) fprintf(outf,"\tName: %-30.30s\n",way->name); + } + if(!way->wpt_class) + (void) fprintf(outf,"\tAltitude: %d\n",(int)way->alt); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_Way154 ************************************ +** +** Output waypoint D154 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way154(GPS_PWay way, FILE *outf) +{ + char **p; + int32 x; + + if(way->smbl < 8192) + { + p = gps_marine_sym; + x = 0; + } + else if(way->smbl < 16384) + { + p = gps_land_sym; + x = 8192; + } + else + { + p = gps_aviation_sym; + x = 16384; + } + + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + (void) fprintf(outf,"\tSymbol: %-6d [%s]\n",(int)way->smbl, + p[way->smbl-x]); + (void) fprintf(outf,"\tClass: %d\n",way->wpt_class); + if(way->wpt_class!=4 && way->wpt_class!=8) + { + (void) fprintf(outf,"\tCountry: %-2.2s\n",way->cc); + (void) fprintf(outf,"\tCity: %-24.24s\n",way->city); + (void) fprintf(outf,"\tState: %-2.2s\n",way->state); + (void) fprintf(outf,"\tName: %-30.30s\n",way->name); + } + if(!way->wpt_class) + (void) fprintf(outf,"\tAltitude: %d\n",(int)way->alt); + + return; +} + + +/* @funcstatic GPS_Fmt_Print_Way155 ************************************* +** +** Output waypoint D155 +** +** @param [r] way [GPS_PWay] waypoint +** @param [w] outf [FILE *] output stream +** +** @return [void] +************************************************************************/ + +static void GPS_Fmt_Print_Way155(GPS_PWay way, FILE *outf) +{ + static char *dspl[]= + { + "","S","","SW","","SC" + }; + + char **p; + int32 x; + + if(way->smbl < 8192) + { + p = gps_marine_sym; + x = 0; + } + else if(way->smbl < 16384) + { + p = gps_land_sym; + x = 8192; + } + else + { + p = gps_aviation_sym; + x = 16384; + } + + + (void) fprintf(outf,"\tIdent: %-6.6s\n",way->ident); + (void) fprintf(outf,"\tLatitude: %f\n",way->lat); + (void) fprintf(outf,"\tLongitude: %f\n",way->lon); + (void) fprintf(outf,"\tComment: %-40.40s\n",way->cmnt); + (void) fprintf(outf,"\tSymbol: %-6d [%s]\n",(int)way->smbl, + p[way->smbl-x]); + (void) fprintf(outf,"\tDisplay: %-6d [%s]\n",(int)way->dspl, + dspl[way->dspl]); + (void) fprintf(outf,"\tClass: %d\n",way->wpt_class); + if(way->wpt_class!=4 && way->wpt_class!=8) + { + (void) fprintf(outf,"\tCountry: %-2.2s\n",way->cc); + (void) fprintf(outf,"\tCity: %-24.24s\n",way->city); + (void) fprintf(outf,"\tState: %-2.2s\n",way->state); + (void) fprintf(outf,"\tName: %-30.30s\n",way->name); + } + if(!way->wpt_class) + (void) fprintf(outf,"\tAltitude: %d\n",(int)way->alt); + + return; +} + + + +/* @func GPS_Fmt_Print_Route ***************************************** +** +** Output route(s) +** +** @param [r] way [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** @param [w] outf [FILE *] output stream +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Fmt_Print_Route(GPS_PWay *way, int32 n, FILE *outf) +{ + int32 i; + int32 first; + + if(!n) + return 1; + + + switch(gps_route_transfer) + { + case pA200: + break; + case pA201: + return GPS_Fmt_Print_Route201(way,n,outf); + default: + GPS_Error("GPS_Fmt_Print_Route: Unknown protocol"); + return PROTOCOL_ERROR; + } + + + (void) fprintf(outf,"Route log 200 %d\n#\n",(int)gps_rte_type); + (void) fprintf(outf,"Start\n#\n"); + + + + first = 1; + + for(i=0;iisrte) + { + if(!first) + (void) fprintf(outf,"End\n#\n"); + (void) fprintf(outf,"Route Type: %d ",(int)way[i]->rte_prot); + first=0; + + switch(way[i]->rte_prot) + { + case 200: + (void) fprintf(outf,"Number: %d",way[i]->rte_num); + break; + case 201: + (void) fprintf(outf,"Number: %d Comment: %-20.20s", + way[i]->rte_num,way[i]->rte_cmnt); + break; + case 202: + (void) fprintf(outf,"Comment: %s",way[i]->rte_ident); + break; + default: + GPS_Error("Print_Route: Unknown route protocol"); + return PROTOCOL_ERROR; + } + (void) fprintf(outf,"\n#\n"); + (void) fprintf(outf,"Waypoints Type: %d\n#\nStart\n#\n" + ,(int)way[i]->prot); + continue; + } + + switch(way[i]->prot) + { + case 100: + GPS_Fmt_Print_Way100(way[i],outf); + break; + case 101: + GPS_Fmt_Print_Way101(way[i],outf); + break; + case 102: + GPS_Fmt_Print_Way102(way[i],outf); + break; + case 103: + GPS_Fmt_Print_Way103(way[i],outf); + break; + case 104: + GPS_Fmt_Print_Way104(way[i],outf); + break; + case 105: + GPS_Fmt_Print_Way105(way[i],outf); + break; + case 106: + GPS_Fmt_Print_Way106(way[i],outf); + break; + case 107: + GPS_Fmt_Print_Way107(way[i],outf); + break; + case 108: + GPS_Fmt_Print_Way108(way[i],outf); + break; + case 109: + GPS_Fmt_Print_Way109(way[i],outf); + break; + case 150: + GPS_Fmt_Print_Way150(way[i],outf); + break; + case 151: + GPS_Fmt_Print_Way151(way[i],outf); + break; + case 152: + GPS_Fmt_Print_Way152(way[i],outf); + break; + case 154: + GPS_Fmt_Print_Way154(way[i],outf); + break; + case 155: + GPS_Fmt_Print_Way155(way[i],outf); + break; + default: + GPS_Error("Print_Route: Unknown waypoint protocol"); + return PROTOCOL_ERROR; + } + (void) fprintf(outf,"#\n"); + } + (void) fprintf(outf,"End\n#\n"); + + return 1; +} + + + +/* @funcstatic GPS_Fmt_Print_Route201 *********************************** +** +** Output route(s) +** +** @param [r] way [GPS_PWay *] waypoint array +** @param [r] n [int32] number of waypoint entries +** @param [w] outf [FILE *] output stream +** +** @return [int32] success +************************************************************************/ + +static int32 GPS_Fmt_Print_Route201(GPS_PWay *way, int32 n, FILE *outf) +{ + int32 i; + int32 first; + + if(!n) + return 1; + + + (void) fprintf(outf,"Route log 201 %d\n#\n",(int)gps_rte_link_type); + (void) fprintf(outf,"Start\n#\n"); + + + first = 1; + + for(i=0;iisrte) + { + if(!first) + (void) fprintf(outf,"End\n#\n"); + (void) fprintf(outf,"Route Type: %d ",(int)way[i]->rte_prot); + first=0; + + switch(way[i]->rte_prot) + { + case 200: + (void) fprintf(outf,"Number: %d",way[i]->rte_num); + break; + case 201: + (void) fprintf(outf,"Number: %d Comment: %-20.20s", + way[i]->rte_num,way[i]->rte_cmnt); + break; + case 202: + (void) fprintf(outf,"Comment: %s",way[i]->rte_ident); + break; + default: + GPS_Error("Print_Route: Unknown route protocol"); + return PROTOCOL_ERROR; + } + (void) fprintf(outf,"\n#\n"); + (void) fprintf(outf,"Waypoints Type: %d\n#\n" + ,(int)way[i]->prot); + continue; + } + + + if(way[i]->islink) + { + (void) fprintf(outf,"\tLink Class: %d\n", + (int)way[i]->rte_link_class); + if(!(way[i]->rte_link_class==3 || way[i]->rte_link_class==0xff)) + (void) fprintf(outf,"\tLink Subclass: %-18.18s\n", + way[i]->rte_link_subclass); + (void) fprintf(outf,"\tLink Ident: %s\n#\n", + way[i]->rte_link_ident); + continue; + } + + + switch(way[i]->prot) + { + case 100: + GPS_Fmt_Print_Way100(way[i],outf); + break; + case 101: + GPS_Fmt_Print_Way101(way[i],outf); + break; + case 102: + GPS_Fmt_Print_Way102(way[i],outf); + break; + case 103: + GPS_Fmt_Print_Way103(way[i],outf); + break; + case 104: + GPS_Fmt_Print_Way104(way[i],outf); + break; + case 105: + GPS_Fmt_Print_Way105(way[i],outf); + break; + case 106: + GPS_Fmt_Print_Way106(way[i],outf); + break; + case 107: + GPS_Fmt_Print_Way107(way[i],outf); + break; + case 108: + GPS_Fmt_Print_Way108(way[i],outf); + break; + case 109: + GPS_Fmt_Print_Way109(way[i],outf); + break; + case 150: + GPS_Fmt_Print_Way150(way[i],outf); + break; + case 151: + GPS_Fmt_Print_Way151(way[i],outf); + break; + case 152: + GPS_Fmt_Print_Way152(way[i],outf); + break; + case 154: + GPS_Fmt_Print_Way154(way[i],outf); + break; + case 155: + GPS_Fmt_Print_Way155(way[i],outf); + break; + default: + GPS_Error("Print_Route: Unknown waypoint protocol"); + return PROTOCOL_ERROR; + } + (void) fprintf(outf,"#\n"); + } + (void) fprintf(outf,"End\n"); + + return 1; +} diff --git a/jeeps/gpsfmt.h b/jeeps/gpsfmt.h new file mode 100644 index 000000000..f9eaae32c --- /dev/null +++ b/jeeps/gpsfmt.h @@ -0,0 +1,27 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsfmt_h +#define gpsfmt_h + + +#include "gps.h" +#include +#include + +void GPS_Fmt_Print_Time(time_t Time, FILE *outf); +void GPS_Fmt_Print_Position(double lat, double lon, FILE *outf); +void GPS_Fmt_Print_Pvt(GPS_PPvt_Data pvt, FILE *outf); +void GPS_Fmt_Print_Almanac(GPS_PAlmanac *alm, int32 n, FILE *outf); +void GPS_Fmt_Print_Track(GPS_PTrack *trk, int32 n, FILE *outf); +int32 GPS_Fmt_Print_Waypoint(GPS_PWay *way, int32 n, FILE *outf); +int32 GPS_Fmt_Print_Proximity(GPS_PWay *way, int32 n, FILE *outf); +int32 GPS_Fmt_Print_Route(GPS_PWay *way, int32 n, FILE *outf); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsinput.c b/jeeps/gpsinput.c new file mode 100644 index 000000000..ad3e99b6e --- /dev/null +++ b/jeeps/gpsinput.c @@ -0,0 +1,2253 @@ +/******************************************************************** +** @source JEEPS input functions +** +** @author Copyright (C) 1999 Alan Bleasby +** @version 1.0 +** @modified Dec 28 1999 Alan Bleasby. First version +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include +#include +#include +#include + + +static int32 GPS_Input_Load_String(char *t, int32 n, char *s); +static int32 GPS_Input_Load_Strnull(char *t, char *s); +static int32 GPS_Input_Read_Line(char *s, FILE *inf); + +static int32 GPS_Input_Get_D100(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D101(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D102(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D103(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D104(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D105(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D106(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D107(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D108(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D109(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D150(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D151(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D152(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D154(GPS_PWay *way, FILE *inf); +static int32 GPS_Input_Get_D155(GPS_PWay *way, FILE *inf); + +static int32 GPS_Input_Get_Track301(GPS_PTrack **trk, FILE *inf, int32 type, + int32 n); +static int32 GPS_Input_Get_D300(GPS_PTrack *trk, FILE *inf, char *s); +static int32 GPS_Input_Get_D301(GPS_PTrack *trk, FILE *inf, char *s); + +static int32 GPS_Input_Get_Route201(GPS_PWay **way, FILE *inf); + + +/* @funcstatic GPS_Input_Load_String *********************************** +** +** Load a GPS char type from an input line +** Remove trailing newline +** +** @param [w] t [char *] string to load +** @param [r] n [int32] maximum type length +** @param [r] s [char *] source line +** +** @return [int32] success +************************************************************************/ +static int32 GPS_Input_Load_String(char *t, int32 n, char *s) +{ + char *p; + char *q; + + int32 len; + int32 i; + + gps_errno = INPUT_ERROR; + + p=s; + if(!(p=strchr(p,':'))) + return gps_errno; + ++p; + while(*p && (*p==' ' || *p=='\t')) ++p; + if(!*p) + return 0; + + len = strlen(p); + q = p+len-1; + while(*q==' ' || *q=='\t') --q; + len = q-p+1; + + if(q-p+1 > n) + { + len = n; + p[n]='\0'; + } + for(i=0;isvid = i; + (*alm)[i]->wn = -1; + } + } + else + { + if(!(*alm = (GPS_PAlmanac *) malloc(n*sizeof(GPS_PAlmanac *)))) + return MEMORY_ERROR; + for(i=0;i<32;++i) + if(!((*alm)[i] = GPS_Almanac_New())) + return MEMORY_ERROR; + } + + for(i=0;isvid!=d) ++i; + (*alm)[i]->svid=d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*alm)[i]->wn = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%f",&f)!=1) + return gps_errno; + (*alm)[i]->toa = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%f",&f)!=1) + return gps_errno; + (*alm)[i]->af0 = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%f",&f)!=1) + return gps_errno; + (*alm)[i]->af1 = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%f",&f)!=1) + return gps_errno; + (*alm)[i]->e = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%f",&f)!=1) + return gps_errno; + (*alm)[i]->sqrta = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%f",&f)!=1) + return gps_errno; + (*alm)[i]->m0 = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%f",&f)!=1) + return gps_errno; + (*alm)[i]->w = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%f",&f)!=1) + return gps_errno; + (*alm)[i]->omg0 = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%f",&f)!=1) + return gps_errno; + (*alm)[i]->odot = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%f",&f)!=1) + return gps_errno; + (*alm)[i]->i = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*alm)[i]->hlth=d; + } + + if(!type) + n = 32; + + return n; +} + + + +/* @func GPS_Input_Get_Waypoint ***************************************** +** +** Construct a waypoint array from a file +** +** @param [w] way [GPS_PWay **] pointer to waypoint array +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ + +int32 GPS_Input_Get_Waypoint(GPS_PWay **way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + int32 n; + int32 type; + int32 i; + long pos; + int32 ret; + + gps_errno = INPUT_ERROR; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(sscanf(s,"Waypoints Type: %d",(int *)&type)!=1) + return gps_errno; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(strncmp(s,"Start",5)) + return gps_errno; + + pos = ftell(inf); + n = 0; + while(strncmp(s,"End",3)) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(strstr(s,"Latitude")) + ++n; + } + fseek(inf,pos,0); + + if(!(*way=(GPS_PWay *)malloc(n*sizeof(GPS_PWay *)))) + return MEMORY_ERROR; + for(i=0;iprot = type; + } + + + for(i=0;iprot = type; + } + + for(i=0;idst = f; + } + + return n; +} + + + +/* @funcstatic GPS_Input_Get_D100 ************************************ +** +** Get a D100 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D100(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + + double f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->ident,6,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cmnt,40,s); + + return 1; +} + + + +/* @funcstatic GPS_Input_Get_D101 ************************************ +** +** Get a D101 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D101(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + + double f; + int32 d; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->ident,6,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cmnt,40,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->smbl = d; + + return 1; +} + + + +/* @funcstatic GPS_Input_Get_D102 ************************************ +** +** Get a D102 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D102(GPS_PWay *way, FILE *inf) +{ + return GPS_Input_Get_D101(way,inf); +} + + + +/* @funcstatic GPS_Input_Get_D103 ************************************ +** +** Get a D103 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D103(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + + double f; + int32 d; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->ident,6,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cmnt,40,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->smbl = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->dspl = d; + + return 1; +} + + + +/* @funcstatic GPS_Input_Get_D104 ************************************ +** +** Get a D104 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D104(GPS_PWay *way, FILE *inf) +{ + return GPS_Input_Get_D103(way,inf); +} + + + +/* @funcstatic GPS_Input_Get_D105 ************************************ +** +** Get a D105 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D105(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + + double f; + int32 d; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->smbl = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->wpt_ident,s); + + return 1; +} + + + +/* @funcstatic GPS_Input_Get_D106 ************************************ +** +** Get a D106 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D106(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + + double f; + int32 d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->wpt_class = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((char *)(*way)->subclass,13,s); + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->ident,6,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->smbl = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->wpt_ident,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->lnk_ident,s); + + return 1; +} + + + +/* @funcstatic GPS_Input_Get_D107 ************************************ +** +** Get a D107 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D107(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + + int32 d; + int32 ret; + + if((ret=GPS_Input_Get_D103(way,inf))<0) + return ret; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->colour = d; + + return 1; +} + + + +/* @funcstatic GPS_Input_Get_D108 ************************************ +** +** Get a D108 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D108(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + double f; + int32 d; + int32 xc; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->ident,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->colour = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->dspl = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->smbl = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->alt = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->dpth = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->state,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cc,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->wpt_class = d; + xc = d; + + if(xc>=0x80 && xc<=0x85) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((char *)(*way)->subclass,18,s); + } + else + { + GPS_Util_Put_Short((*way)->subclass,0); + GPS_Util_Put_Int((*way)->subclass+2,0); + GPS_Util_Put_Uint((*way)->subclass+6,0xffffffff); + GPS_Util_Put_Uint((*way)->subclass+10,0xffffffff); + GPS_Util_Put_Uint((*way)->subclass+14,0xffffffff); + } + + if(!xc) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->cmnt,s); + } + + if(xc>=0x40 && xc<=0x46) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->facility,s); + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->city,s); + } + + if(xc==0x83) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->addr,s); + } + + if(xc==0x82) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->cross_road,s); + } + + return 1; +} + + + +/* @funcstatic GPS_Input_Get_D109 ************************************ +** +** Get a D109 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D109(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + double f; + int32 d; + int32 xc; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->ident,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->colour = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->dspl = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->smbl = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->alt = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->dpth = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->state,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cc,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->wpt_class = d; + xc = d; + + if(xc>=0x80 && xc<=0x85) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((char *)(*way)->subclass,18,s); + } + else + { + GPS_Util_Put_Short((*way)->subclass,0); + GPS_Util_Put_Int((*way)->subclass+2,0); + GPS_Util_Put_Uint((*way)->subclass+6,0xffffffff); + GPS_Util_Put_Uint((*way)->subclass+10,0xffffffff); + GPS_Util_Put_Uint((*way)->subclass+14,0xffffffff); + } + + if(!xc) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->cmnt,s); + } + + if(xc>=0x40 && xc<=0x46) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->facility,s); + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->city,s); + } + + if(xc==0x83) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->addr,s); + } + + if(xc==0x82) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)->cross_road,s); + } + + return 1; +} + + +/* @funcstatic GPS_Input_Get_D150 ************************************ +** +** Get a D150 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D150(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + + double f; + int32 d; + int32 cl=0; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->ident,6,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cmnt,40,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->wpt_class = cl = d; + + if(cl != 4) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cc,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->city,24,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->state,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->name,30,s); + } + + if(!cl) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->alt = d; + } + + return 1; +} + + + +/* @funcstatic GPS_Input_Get_D151 ************************************ +** +** Get a D151 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D151(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + + double f; + int32 d; + int32 cl=0; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->ident,6,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cmnt,40,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->wpt_class = cl = d; + + if(cl != 2) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cc,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->city,24,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->state,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->name,30,s); + } + + if(!cl) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->alt = d; + } + + return 1; +} + + +/* @funcstatic GPS_Input_Get_D152 ************************************ +** +** Get a D152 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D152(GPS_PWay *way, FILE *inf) +{ + return GPS_Input_Get_D150(way,inf); +} + + + +/* @funcstatic GPS_Input_Get_D154 ************************************ +** +** Get a D154 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D154(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + + double f; + int32 d; + int32 cl=0; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->ident,6,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cmnt,40,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->smbl = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->wpt_class = cl = d; + + if(cl != 4 && cl != 8) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cc,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->city,24,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->state,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->name,30,s); + } + + if(!cl) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->alt = d; + } + + return 1; +} + + + +/* @funcstatic GPS_Input_Get_D155 ************************************ +** +** Get a D155 Entry +** +** @param [w] way [GPS_PWay *] pointer to waypoint entry +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ +static int32 GPS_Input_Get_D155(GPS_PWay *way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + char *p; + + double f; + int32 d; + int32 cl=0; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->ident,6,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*way)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cmnt,40,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->smbl = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->dspl = d; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->wpt_class = cl = d; + + if(cl != 4 && cl != 8) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->cc,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->city,24,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->state,2,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)->name,30,s); + } + + if(!cl) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_errno; + (*way)->alt = d; + } + + return 1; +} + + + +/* @func GPS_Input_Get_Track ******************************************* +** +** Construct a travk array from a file +** +** @param [w] trk [GPS_PTrack **] pointer to track array +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ + +int32 GPS_Input_Get_Track(GPS_PTrack **trk, FILE *inf) +{ + char s[GPS_ARB_LEN]; + int32 n; + int32 i; + long pos; + int32 a; + int32 d; + + gps_errno = INPUT_ERROR; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(strncmp(s,"Track log",9)) + return gps_errno; + + if(sscanf(s,"Track log %d%d",(int *)&a,(int *)&d)!=2) + return INPUT_ERROR; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(strncmp(s,"Start",5)) + return gps_errno; + + pos = ftell(inf); + n = 0; + while(strncmp(s,"End",3)) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(strstr(s,"Latitude")) + ++n; + if(strstr(s,"Header")) + ++n; + } + fseek(inf,pos,0); + + + if(!(*trk=(GPS_PTrack *)malloc(n*sizeof(GPS_PTrack *)))) + return MEMORY_ERROR; + for(i=0;itnew=1; + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + } + else + (*trk)[i]->tnew=0; + + switch(d) + { + case pD300: + GPS_Input_Get_D300(&((*trk)[i]),inf,s); + break; + case pD301: + GPS_Input_Get_D301(&((*trk)[i]),inf,s); + break; + default: + return PROTOCOL_ERROR; + } + } + + return n; +} + + + +/* @funcstatic GPS_Input_Get_Track301 ********************************** +** +** Construct a travk array from a file +** +** @param [w] trk [GPS_PTrack **] pointer to track array +** @param [r] inf [FILE *] stream +** @param [r] type [int32] data type +** @param [r] n [int32] number of tracks +** +** @return [int32] number of entries +************************************************************************/ + +static int32 GPS_Input_Get_Track301(GPS_PTrack **trk, FILE *inf, int32 type, + int32 n) +{ + char s[GPS_ARB_LEN]; + int32 i; + char *p; + int32 x; + + for(i=0;iishdr = 1; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*trk)[i]->trk_ident,s); + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&x)!=1) + return INPUT_ERROR; + (*trk)[i]->dspl = x; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&x)!=1) + return INPUT_ERROR; + (*trk)[i]->colour = x; + + continue; + } + + (*trk)[i]->ishdr = 0; + + if(!strcmp(s,"New track")) + { + (*trk)[i]->tnew=1; + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + } + else + (*trk)[i]->tnew=0; + + switch(type) + { + case pD300: + GPS_Input_Get_D300(&((*trk)[i]),inf,s); + break; + case pD301: + GPS_Input_Get_D301(&((*trk)[i]),inf,s); + break; + default: + return PROTOCOL_ERROR; + } + } + + return n; +} + + + +/* @funcstatic GPS_Input_Get_D300 ********************************** +** +** Construct a track from a file +** +** @param [w] trk [GPS_PTrack *] pointer to track +** @param [r] inf [FILE *] stream +** @param [w] s [char *] input line +** +** @return [int32] number of entries +************************************************************************/ + +static int32 GPS_Input_Get_D300(GPS_PTrack *trk, FILE *inf, char *s) +{ + char *p; + double f; + + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*trk)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*trk)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + (*trk)->Time = 0; + + return 1; +} + + + +/* @funcstatic GPS_Input_Get_D301 ********************************** +** +** Construct a track from a file +** +** @param [w] trk [GPS_PTrack *] pointer to track +** @param [r] inf [FILE *] stream +** @param [w] s [char *] input line +** +** @return [int32] number of entries +************************************************************************/ + +static int32 GPS_Input_Get_D301(GPS_PTrack *trk, FILE *inf, char *s) +{ + char *p; + double f; + + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*trk)->lat = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*trk)->lon = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + (*trk)->Time = 0; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*trk)->alt = f; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + p=strchr(s,':'); + if(sscanf(p+1,"%lf",&f)!=1) + return gps_errno; + (*trk)->dpth = f; + + return 1; +} + + + +/* @func GPS_Input_Get_Route ******************************************* +** +** Construct a route array from a file +** +** @param [w] way [GPS_PWay **] pointer to waypoint array +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ + +int32 GPS_Input_Get_Route(GPS_PWay **way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + int32 n; + int32 type; + int32 rtype=0; + int32 atype=0; + int32 i; + long pos; + int32 ret; + char *p; + int32 d; + + gps_errno = INPUT_ERROR; + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(sscanf(s,"Route log %d",(int *)&atype)!=1) + return gps_errno; + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + + switch(atype) + { + case pA200: + break; + case pA201: + return GPS_Input_Get_Route201(way,inf); + default: + GPS_Error("GPS_Input_Get_Route: Unknown protocol"); + return PROTOCOL_ERROR; + } + + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(sscanf(s,"Route Type: %d",(int *)&rtype)!=1) + return gps_errno; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(sscanf(s,"Waypoints Type: %d",(int *)&type)!=1) + return gps_errno; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(strncmp(s,"Start",5)) + return gps_errno; + + pos = ftell(inf); + n = 1; + while(strncmp(s,"End",3)) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(strstr(s,"Latitude") || strstr(s,"Route")) + ++n; + } + fseek(inf,0L,0); + + + if(!(*way=(GPS_PWay *)malloc(n*sizeof(GPS_PWay *)))) + return MEMORY_ERROR; + for(i=0;iprot = type; + } + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + + for(i=0;irte_prot = rtype; + (*way)[i]->islink = 0; + if(strstr(s,"Route")) + { + (*way)[i]->isrte = 1; + switch(rtype) + { + case 200: + p = strchr(s,':'); + p = strchr(p+1,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_error; + (*way)[i]->rte_num=d; + break; + case 201: + p = strchr(s,':'); + p = strchr(p+1,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_error; + (*way)[i]->rte_num=d; + ++p; + GPS_Input_Load_String((*way)[i]->rte_cmnt,20,p+2); + break; + case 202: + p = strchr(s,':'); + p = strchr(p+1,':'); + GPS_Input_Load_Strnull((*way)[i]->rte_ident,p+1); + break; + } + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + continue; + } + else + (*way)[i]->isrte=0; + + if(strstr(s,"End")) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + + continue; + } + + + switch(type) + { + case 100: + ret = GPS_Input_Get_D100(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 101: + ret = GPS_Input_Get_D101(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 102: + ret = GPS_Input_Get_D102(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 103: + ret = GPS_Input_Get_D103(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 104: + ret = GPS_Input_Get_D104(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 105: + ret = GPS_Input_Get_D105(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 106: + ret = GPS_Input_Get_D106(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 107: + ret = GPS_Input_Get_D107(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 108: + ret = GPS_Input_Get_D108(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 150: + ret = GPS_Input_Get_D150(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 151: + ret = GPS_Input_Get_D151(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 152: + ret = GPS_Input_Get_D152(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 154: + ret = GPS_Input_Get_D154(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 155: + ret = GPS_Input_Get_D155(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + default: + GPS_Error("Input_Get_Waypoints: Unknown protocol"); + return PROTOCOL_ERROR; + } + + } + + return n; +} + + + +/* @funcstatic GPS_Input_Get_Route201 *********************************** +** +** Construct a route array from a file +** +** @param [w] way [GPS_PWay **] pointer to waypoint array +** @param [r] inf [FILE *] stream +** +** @return [int32] number of entries +************************************************************************/ + +static int32 GPS_Input_Get_Route201(GPS_PWay **way, FILE *inf) +{ + char s[GPS_ARB_LEN]; + int32 n; + int32 type; + int32 rtype; + int32 i; + long pos; + int32 ret; + char *p; + int32 d; + + gps_errno = INPUT_ERROR; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(sscanf(s,"Route Type: %d",(int *)&rtype)!=1) + return gps_errno; + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(sscanf(s,"Waypoints Type: %d",(int *)&type)!=1) + return gps_errno; + + + pos = ftell(inf); + n = 1; + while(strncmp(s,"End",3)) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(strstr(s,"Latitude") || strstr(s,"Route") || strstr(s,"Link Class")) + ++n; + } + fseek(inf,0L,0); + + if(!(*way=(GPS_PWay *)malloc(n*sizeof(GPS_PWay *)))) + return MEMORY_ERROR; + for(i=0;iprot = type; + } + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + + for(i=0;irte_prot = rtype; + (*way)[i]->islink = 0; + if(strstr(s,"Route")) + { + (*way)[i]->isrte = 1; + switch(rtype) + { + case 200: + p = strchr(s,':'); + p = strchr(p+1,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_error; + (*way)[i]->rte_num=d; + break; + case 201: + p = strchr(s,':'); + p = strchr(p+1,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_error; + (*way)[i]->rte_num=d; + p = strchr(p+1,':'); + GPS_Input_Load_String((*way)[i]->rte_cmnt,20,p+1); + break; + case 202: + p = strchr(s,':'); + p = strchr(p+1,':'); + GPS_Input_Load_Strnull((*way)[i]->rte_ident,p+1); + break; + } + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + continue; + } + else + (*way)[i]->isrte=0; + + + + if(strstr(s,"Link Class")) + { + (*way)[i]->islink = 1; + + p = strchr(s,':'); + if(sscanf(p+1,"%d",(int *)&d)!=1) + return gps_error; + (*way)[i]->rte_link_class=d; + + if(!((*way)[i]->rte_link_class==3 || (*way)[i]->rte_link_class + ==0xff)) + { + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_String((*way)[i]->rte_link_subclass,18,s); + } + else + { + GPS_Util_Put_Short((UC *)(*way)[i]->rte_link_subclass,0); + GPS_Util_Put_Int((UC *)(*way)[i]->rte_link_subclass+2,0); + GPS_Util_Put_Uint((UC *)(*way)[i]->rte_link_subclass+6, + 0xffffffff); + GPS_Util_Put_Uint((UC *)(*way)[i]->rte_link_subclass+10, + 0xffffffff); + GPS_Util_Put_Uint((UC *)(*way)[i]->rte_link_subclass+14, + 0xffffffff); + } + + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + GPS_Input_Load_Strnull((*way)[i]->rte_link_ident,s); + + continue; + } + else + (*way)[i]->islink=0; + + + if(strstr(s,"End")) + { + GPS_Error("Get_Route201: Unexpected End"); + return INPUT_ERROR; + } + + + switch(type) + { + case 100: + ret = GPS_Input_Get_D100(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 101: + ret = GPS_Input_Get_D101(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 102: + ret = GPS_Input_Get_D102(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 103: + ret = GPS_Input_Get_D103(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 104: + ret = GPS_Input_Get_D104(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 105: + ret = GPS_Input_Get_D105(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 106: + ret = GPS_Input_Get_D106(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 107: + ret = GPS_Input_Get_D107(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 108: + ret = GPS_Input_Get_D108(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 150: + ret = GPS_Input_Get_D150(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 151: + ret = GPS_Input_Get_D151(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 152: + ret = GPS_Input_Get_D152(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 154: + ret = GPS_Input_Get_D154(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + case 155: + ret = GPS_Input_Get_D155(&((*way)[i]),inf); + if(ret<0) return gps_errno; + break; + default: + GPS_Error("Input_Get_Waypoints: Unknown protocol"); + return PROTOCOL_ERROR; + } + if(!GPS_Input_Read_Line(s,inf)) + return gps_errno; + } + + return n; +} diff --git a/jeeps/gpsinput.h b/jeeps/gpsinput.h new file mode 100644 index 000000000..5b0e41615 --- /dev/null +++ b/jeeps/gpsinput.h @@ -0,0 +1,23 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsinput_h +#define gpsinput_h + + +#include "gps.h" + +int32 GPS_Input_Get_Almanac(GPS_PAlmanac **alm, FILE *inf); +int32 GPS_Input_Get_Waypoint(GPS_PWay **way, FILE *inf); +int32 GPS_Input_Get_Proximity(GPS_PWay **way, FILE *inf); +int32 GPS_Input_Get_Track(GPS_PTrack **trk, FILE *inf); +int32 GPS_Input_Get_Route(GPS_PWay **way, FILE *inf); + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpslibusb.c b/jeeps/gpslibusb.c new file mode 100644 index 000000000..b8c5868b4 --- /dev/null +++ b/jeeps/gpslibusb.c @@ -0,0 +1,274 @@ +#if !defined(NO_USB) +/* + Physical/OS USB layer to talk to libusb. + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + + +#include +#include +#include "gps.h" +#include "garminusb.h" + +#define GARMIN_VID 0x91e + +/* This is very sensitive to timing; libusb and/or the unit is kind of + * sloppy about not obeying packet boundries. If this is too high, the + * multiple packets responding to the device inquriy will be glommed into + * one packet and we'll misparse them. If it's too low, we'll get partially + * satisfied reads. + */ +#define TMOUT_I 0015 /* Milliseconds to timeout intr pipe access. */ + +int gusb_intr_in_ep; +int gusb_bulk_out_ep; +int gusb_bulk_in_ep; + +static const char oinit[12] = {0, 0, 0, 0, 0x05, 0, 0, 0, 0, 0, 0, 0}; +garmin_usb_packet iresp; + +static struct usb_bus *busses; +static usb_dev_handle *udev; +static void garmin_usb_scan(void); +static void garmin_usb_syncup(void); + +gusb_init(void) +{ +//usb_set_debug(99); + usb_init(); + usb_find_busses(); + usb_find_devices(); + busses = usb_get_busses(); + garmin_usb_scan(); + + return 1; +} + +dump(char *msg, const unsigned char *in, int r) +{ + int i; + printf("%s: %d\n", msg, r); + for (i = 0; i < r; i++) { + printf ("%02x ", in[i]); + } + if (r) printf("\n"); + for (i = 0; i < r; i++) { + printf ("%c", isalnum(in[i]) ? in[i] : '.'); + } + if (r) printf("\n"); +} + +int +gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz) +{ + int r; + + r = usb_bulk_write(udev, gusb_bulk_out_ep, &opkt->dbuf, sz, TMOUT_I); + dump ("Sent", &opkt->dbuf[0], r); + if (r != sz) { + fprintf(stderr, "Bad cmdsend\n"); + } +} +#if 0 +int +gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz) +{ + int rv = 0; + unsigned char *obuf = &ibuf->dbuf; + unsigned char *buf = obuf; + + while (sz) { + int r; + /* + * Since Garmin stupidly put bulk data on an interrupt pipe + * with an absurdly tiny buffer, we have to coalesce reads + * and we have to be fast about getting them. (High speed + * polling totally misses the point of USB...) + */ + + r = usb_interrupt_read(udev, gusb_intr_in_ep, buf, sz, TMOUT_I); + printf("Read: %d/%d \n", r, sz); + if (r > 0) { + buf += r; + rv += r; + sz -= r; + } + if (r < 0) return rv; + /* + * A zero length read AFTER a successful read means we're + * done. + */ + if (r == 0 && rv) { + break; + } + } + dump("completed intr Got", obuf, rv); + return rv; +} +#else + +int +gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz) +{ + unsigned char *buf = &ibuf->dbuf[0]; + unsigned char *obuf = buf; + int r = -1, tsz = 0; + while (r <= 0) + r = usb_interrupt_read(udev, gusb_intr_in_ep, buf, sz, TMOUT_I); + + tsz = r; + + if (gps_show_bytes) { + int i; + const char *m1, *m2; + printf("RX [%d]:", tsz); + for(i=0;igusb_pkt.pkt_id[0], ibuf->gusb_pkt.databuf[0], &m2); + GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); + printf("\n"); + } + + return (r); + + +} +#endif + +void +garmin_usb_teardown(void) +{ + if (udev) { + fprintf(stderr, "Tearing down\n"); + usb_release_interface(udev, 0); + usb_close(udev); + udev = NULL; + } +} + +garmin_usb_start(struct usb_device *dev) +{ + int ret; + int i; + char ibuf[4096]; + + udev = usb_open(dev); + atexit(garmin_usb_teardown); + if (!udev) { fatal("usb_open failed"); } + /* + * Hrmph. No iManufacturer or iProduct headers.... + */ + if (usb_claim_interface(udev, 0) < 0) { + abort(); + } + + if (usb_set_configuration(udev, 1) < 0) { + abort(); + } + + + for (i = 0; i < dev->config->interface->altsetting->bNumEndpoints; i++) { + struct usb_endpoint_descriptor * ep; + ep = &dev->config->interface->altsetting->endpoint[i]; + switch (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) { +#define EA(x) x & USB_ENDPOINT_ADDRESS_MASK + case USB_ENDPOINT_TYPE_BULK: + if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + gusb_bulk_in_ep = EA(ep->bEndpointAddress); + else + gusb_bulk_out_ep = EA(ep->bEndpointAddress); + break; + case USB_ENDPOINT_TYPE_INTERRUPT: + if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + gusb_intr_in_ep = EA(ep->bEndpointAddress); + break; + } + } +//printf("Bulk in: %d\n", gusb_bulk_in_ep); +//printf("Bulk out: %d\n", gusb_bulk_out_ep); +//printf("intr in: %d\n", gusb_intr_in_ep); + + garmin_usb_syncup(); + +// fprintf(stdout, "====================================================\n"); + + return; + usb_release_interface(udev, 0); + usb_reset(udev); + usb_close(udev); +exit(1); +} + +void +garmin_usb_syncup(void) +{ + int maxct = 5; + int maxtries; + char ibuf[4096]; +#if 0 + usb_clear_halt(udev, gusb_intr_in_ep); + usb_clear_halt(udev, gusb_bulk_out_ep); + usb_clear_halt(udev, gusb_bulk_in_ep); +#endif + + for (maxtries = maxct; maxtries; maxtries--) { + + le_write16(&iresp.gusb_pkt.pkt_id, 0); + le_write32(&iresp.gusb_pkt.datasz, 0); + le_write32(&iresp.gusb_pkt.databuf, 0); + + gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit)); + gusb_cmd_get(&iresp, sizeof(iresp)); + + if ((le_read16(iresp.gusb_pkt.pkt_id) == 6) && + (le_read32(iresp.gusb_pkt.datasz) == 4)) { + fprintf(stderr, "Synced in %d\n", maxct - maxtries); +// fprintf(stderr, "Unit number %u\n", iresp[15] << 24 | iresp[14] << 16 | iresp[13] << 8 | iresp[12]); + return; + } + } +return; + fatal("Cannot sync up with receiver\n"); +} + +static +void garmin_usb_scan(void) +{ + struct usb_bus *bus; + int c, i, a; + + for (bus = busses; bus; bus = bus->next) { + struct usb_device *dev; + + for (dev = bus->devices; dev; dev = dev->next) { + /* Probably too promiscious of a match, but since + * Garmin doesn't document the _proper_ matching, + * we just take the easy way out for now. + */ + if (dev->descriptor.idVendor == GARMIN_VID) { + garmin_usb_start(dev); + } + } + } +} + +#endif /* !defined(NO_USB) */ diff --git a/jeeps/gpsmath.c b/jeeps/gpsmath.c new file mode 100644 index 000000000..e3a9284a7 --- /dev/null +++ b/jeeps/gpsmath.c @@ -0,0 +1,1799 @@ +/******************************************************************** +** @source JEEPS arithmetic/conversion functions +** +** @author Copyright (C) 1999 Alan Bleasby +** @version 1.0 +** @modified Dec 28 1999 Alan Bleasby. First version +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include +#include +#include +#include "gpsdatum.h" + + + +static int32 GPS_Math_LatLon_To_UTM_Param(double lat, double lon, int32 *zone, + char *zc, double *Mc, double *E0, + double *N0, double *F0); +static int32 GPS_Math_UTM_Param_To_Mc(int32 zone, char zc, double *Mc, + double *E0, double *N0, double *F0); + + + +/* @func GPS_Math_Deg_To_Rad ******************************************* +** +** Convert degrees to radians +** +** @param [r] v [double] degrees +** +** @return [double] radians +************************************************************************/ + +double GPS_Math_Deg_To_Rad(double v) +{ + return v*(double)((double)GPS_PI/(double)180.); +} + + + +/* @func GPS_Math_Rad_To_Deg ******************************************* +** +** Convert radians to degrees +** +** @param [r] v [double] radians +** +** @return [double] degrees +************************************************************************/ + +double GPS_Math_Rad_To_Deg(double v) +{ + return v*(double)((double)180./(double)GPS_PI); +} + + + +/* @func GPS_Math_Deg_To_DegMin ***************************************** +** +** Convert degrees to degrees and minutes +** +** @param [r] v [double] degrees +** @param [w] d [int32 *] whole degrees +** @param [w] m [double *] minutes +** +** @return [void] +************************************************************************/ + +void GPS_Math_Deg_To_DegMin(double v, int32 *d, double *m) +{ + int32 sign; + + if(v<(double)0.) + { + v *= (double)-1.; + sign = 1; + } + else + sign = 0; + + *d = (int32)v; + *m = (v-(double)*d) * (double)60.0; + if(*m>(double)59.999) + { + ++*d; + *m = (double)0.0; + } + + if(sign) + *d = -*d; + + return; +} + + + +/* @func GPS_Math_DegMin_To_Deg ***************************************** +** +** Convert degrees and minutes to degrees +** +** @param [r] d [int32] whole degrees +** @param [r] m [double] minutes +** @param [w] deg [double *] degrees +** +** @return [void] +************************************************************************/ + +void GPS_Math_DegMin_To_Deg(int32 d, double m, double *deg) +{ + + *deg = ((double)abs(d)) + m / (double)60.0; + if(d<0) + *deg = -*deg; + + return; +} + + + +/* @func GPS_Math_Deg_To_DegMinSec ************************************* +** +** Convert degrees to degrees, minutes and seconds +** +** @param [r] v [double] degrees +** @param [w] d [int32 *] whole degrees +** @param [w] m [int32 *] whole minutes +** @param [w] s [double *] seconds +** +** @return [void] +************************************************************************/ + +void GPS_Math_Deg_To_DegMinSec(double v, int32 *d, int32 *m, double *s) +{ + int32 sign; + double t; + + if(v<(double)0.) + { + v *= (double)-1.; + sign = 1; + } + else + sign = 0; + + *d = (int32)v; + t = (v -(double)*d) * (double)60.0; + *s = (t-(double)*m) * (double)60.0; + + if(*s>(double)59.999) + { + ++t; + *s = (double)0.0; + } + + + if(t>(double)59.999) + { + ++*d; + t = 0; + } + + *m = (int32)t; + + if(sign) + *d = -*d; + + return; +} + + + +/* @func GPS_Math_DegMinSec_To_Deg ***************************************** +** +** Convert degrees, minutes and seconds to degrees +** +** @param [r] d [int32] whole degrees +** @param [r] m [int32] whole minutes +** @param [r] s [double] seconds +** @param [w] deg [double *] degrees +** +** @return [void] +************************************************************************/ + +void GPS_Math_DegMinSec_To_Deg(int32 d, int32 m, double s, double *deg) +{ + + *deg = ((double)abs(d)) + ((double)m + s / (double)60.0) / (double)60.0; + if(d<0) + *deg = -*deg; + + return; +} + + + +/* @func GPS_Math_Metres_To_Feet ******************************************* +** +** Convert metres to feet +** +** @param [r] v [double] metres +** +** @return [double] feet +************************************************************************/ + +double GPS_Math_Metres_To_Feet(double v) +{ + return v/0.3048; +} + + + +/* @func GPS_Math_Feet_To_Metres ******************************************* +** +** Convert feet to metres +** +** @param [r] v [double] feet +** +** @return [double] metres +************************************************************************/ + +double GPS_Math_Feet_To_Metres(double v) +{ + return v * 0.3048; +} + + + +/* @func GPS_Math_Deg_To_Semi ******************************************* +** +** Convert degrees to semi-circles +** +** @param [r] v [double] degrees +** +** @return [int32] semicircles +************************************************************************/ + +int32 GPS_Math_Deg_To_Semi(double v) +{ + return ((1U<<31) / 180) * v; +} + + + +/* @func GPS_Math_Semi_To_Deg ******************************************* +** +** Convert semi-circles to degrees +** +** @param [r] v [int32] semi-circles +** +** @return [double] degrees +************************************************************************/ + +double GPS_Math_Semi_To_Deg(int32 v) +{ + return (double) (((double)v/(double)(1U<<31)) * (double)180); +} + + + +/* @func GPS_Math_Utime_To_Gtime ******************************************* +** +** Convert Unix time (1970) to GPS time (1990) +** +** @param [r] v [time_t] Unix time +** +** @return [time_t] GPS time +************************************************************************/ + +time_t GPS_Math_Utime_To_Gtime(time_t v) +{ + return v-631065600; +} + + + +/* @func GPS_Math_Gtime_To_Utime ******************************************* +** +** Convert GPS time (1990) to Unix time (1970) +** +** @param [r] v [time_t] GPS time +** +** @return [time_t] Unix time +************************************************************************/ + +time_t GPS_Math_Gtime_To_Utime(time_t v) +{ + return v+631065600; +} + + + + +/* @func GPS_Math_LatLonH_To_XYZ ********************************** +** +** Convert latitude and longitude and ellipsoidal height to +** X, Y & Z coordinates +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [r] H [double] ellipsoidal height (metres) +** @param [w] x [double *] X +** @param [w] y [double *] Y +** @param [w] z [double *] Z +** @param [r] a [double] semi-major axis (metres) +** @param [r] b [double] semi-minor axis (metres) +** +** @return [void] +************************************************************************/ +void GPS_Math_LatLonH_To_XYZ(double phi, double lambda, double H, + double *x, double *y, double *z, + double a, double b) +{ + double esq; + double nu; + + phi = GPS_Math_Deg_To_Rad(phi); + lambda = GPS_Math_Deg_To_Rad(lambda); + + + esq = ((a*a)-(b*b)) / (a*a); + + nu = a / pow(((double)1.0-esq*sin(phi)*sin(phi)),(double)0.5); + *x = (nu+H) * cos(phi) * cos(lambda); + *y = (nu+H) * cos(phi) * sin(lambda); + *z = (((double)1.0-esq)*nu+H) * sin(phi); + + return; +} + + + + +/* @func GPS_Math_XYX_To_LatLonH *************************************** +** +** Convert XYZ coordinates to latitude and longitude and ellipsoidal height +** +** @param [w] phi [double] latitude (deg) +** @param [w] lambda [double] longitude (deg) +** @param [w] H [double] ellipsoidal height (metres) +** @param [r] x [double *] X +** @param [r] y [double *] Y +** @param [r] z [double *] Z +** @param [r] a [double] semi-major axis (metres) +** @param [r] b [double] semi-minor axis (metres) +** +** @return [void] +************************************************************************/ +void GPS_Math_XYZ_To_LatLonH(double *phi, double *lambda, double *H, + double x, double y, double z, + double a, double b) +{ + double esq; + double nu=0.0; + double phix; + double nphi; + double rho; + int32 t1=0; + int32 t2=0; + + if(x<(double)0 && y>=(double)0) t1=1; + if(x<(double)0 && y<(double)0) t2=1; + + rho = pow(((x*x)+(y*y)),(double)0.5); + esq = ((a*a)-(b*b)) / (a*a); + phix = atan(z/(((double)1.0 - esq) * rho)); + nphi = (double)1e20; + + while(fabs(phix-nphi)>(double)0.00000000001) + { + nphi = phix; + nu = a / pow(((double)1.0-esq*sin(nphi)*sin(nphi)),(double)0.5); + phix = atan((z+esq*nu*sin(nphi))/rho); + } + + *phi = GPS_Math_Rad_To_Deg(phix); + *H = (rho / cos(phix)) - nu; + *lambda = GPS_Math_Rad_To_Deg(atan(y/x)); + + if(t1) *lambda += (double)180.0; + if(t2) *lambda -= (double)180.0; + + return; +} + + + +/* @func GPS_Math_Airy1830LatLonH_To_XYZ ********************************** +** +** Convert Airy 1830 latitude and longitude and ellipsoidal height to +** X, Y & Z coordinates +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [r] H [double] ellipsoidal height (metres) +** @param [w] x [double *] X +** @param [w] y [double *] Y +** @param [w] z [double *] Z +** +** @return [void] +************************************************************************/ +void GPS_Math_Airy1830LatLonH_To_XYZ(double phi, double lambda, double H, + double *x, double *y, double *z) +{ + double a = 6377563.396; + double b = 6356256.910; + + GPS_Math_LatLonH_To_XYZ(phi,lambda,H,x,y,z,a,b); + + return; +} + + + +/* @func GPS_Math_WGS84LatLonH_To_XYZ ********************************** +** +** Convert WGS84 latitude and longitude and ellipsoidal height to +** X, Y & Z coordinates +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [r] H [double] ellipsoidal height (metres) +** @param [w] x [double *] X +** @param [w] y [double *] Y +** @param [w] z [double *] Z +** +** @return [void] +************************************************************************/ +void GPS_Math_WGS84LatLonH_To_XYZ(double phi, double lambda, double H, + double *x, double *y, double *z) +{ + double a = 6378137.000; + double b = 6356752.3141; + + GPS_Math_LatLonH_To_XYZ(phi,lambda,H,x,y,z,a,b); + + return; +} + + + + +/* @func GPS_Math_XYZ_To_Airy1830LatLonH ********************************** +** +** Convert XYZ to Airy 1830 latitude and longitude and ellipsoidal height +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [r] H [double] ellipsoidal height (metres) +** @param [w] x [double *] X +** @param [w] y [double *] Y +** @param [w] z [double *] Z +** +** @return [void] +************************************************************************/ +void GPS_Math_XYZ_To_Airy1830LatLonH(double *phi, double *lambda, double *H, + double x, double y, double z) +{ + double a = 6377563.396; + double b = 6356256.910; + + GPS_Math_XYZ_To_LatLonH(phi,lambda,H,x,y,z,a,b); + + return; +} + + + +/* @func GPS_Math_XYZ_To_WGS84LatLonH ********************************** +** +** Convert XYZ to WGS84 latitude and longitude and ellipsoidal height +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [r] H [double] ellipsoidal height (metres) +** @param [w] x [double *] X +** @param [w] y [double *] Y +** @param [w] z [double *] Z +** +** @return [void] +************************************************************************/ +void GPS_Math_XYZ_To_WGS84LatLonH(double *phi, double *lambda, double *H, + double x, double y, double z) +{ + double a = 6378137.000; + double b = 66356752.3141; + + GPS_Math_XYZ_To_LatLonH(phi,lambda,H,x,y,z,a,b); + + return; +} + + + + + + + +/* @func GPS_Math_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to eastings and northings +** Standard Gauss-Kruger Transverse Mercator +** +** @param [w] E [double *] easting (metres) +** @param [w] N [double *] northing (metres) +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [r] N0 [double] true northing origin (metres) +** @param [r] E0 [double] true easting origin (metres) +** @param [r] phi0 [double] true latitude origin (deg) +** @param [r] lambda0 [double] true longitude origin (deg) +** @param [r] F0 [double] scale factor on central meridian +** @param [r] a [double] semi-major axis (metres) +** @param [r] b [double] semi-minor axis (metres) +** +** @return [void] +************************************************************************/ +void GPS_Math_LatLon_To_EN(double *E, double *N, double phi, + double lambda, double N0, double E0, + double phi0, double lambda0, + double F0, double a, double b) +{ + double esq; + double n; + double etasq; + double nu; + double rho; + double M; + double I; + double II; + double III; + double IIIA; + double IV; + double V; + double VI; + + double tmp; + double tmp2; + double fdf; + double fde; + + phi0 = GPS_Math_Deg_To_Rad(phi0); + lambda0 = GPS_Math_Deg_To_Rad(lambda0); + phi = GPS_Math_Deg_To_Rad(phi); + lambda = GPS_Math_Deg_To_Rad(lambda); + + esq = ((a*a)-(b*b)) / (a*a); + n = (a-b) / (a+b); + + tmp = (double)1.0 - (esq * sin(phi) * sin(phi)); + nu = a * F0 * pow(tmp,(double)-0.5); + rho = a * F0 * ((double)1.0 - esq) * pow(tmp,(double)-1.5); + etasq = (nu / rho) - (double)1.0; + + fdf = (double)5.0 / (double)4.0; + tmp = (double)1.0 + n + (fdf * n * n) + (fdf * n * n * n); + tmp *= (phi - phi0); + tmp2 = (double)3.0*n + (double)3.0*n*n + ((double)21./(double)8.)*n*n*n; + tmp2 *= (sin(phi-phi0) * cos(phi+phi0)); + tmp -= tmp2; + + fde = ((double)15.0 / (double)8.0); + tmp2 = ((fde*n*n) + (fde*n*n*n)) * sin((double)2.0 * (phi-phi0)); + tmp2 *= cos((double)2.0 * (phi+phi0)); + tmp += tmp2; + + tmp2 = ((double)35.0/(double)24.0) * n * n * n; + tmp2 *= sin((double)3.0 * (phi-phi0)); + tmp2 *= cos((double)3.0 * (phi+phi0)); + tmp -= tmp2; + + M = b * F0 * tmp; + I = M + N0; + II = (nu / (double)2.0) * sin(phi) * cos(phi); + III = (nu / (double)24.0) * sin(phi) * cos(phi) * cos(phi) * cos(phi); + III *= ((double)5.0 - (tan(phi) * tan(phi)) + ((double)9.0 * etasq)); + IIIA = (nu / (double)720.0) * sin(phi) * pow(cos(phi),(double)5.0); + IIIA *= ((double)61.0 - ((double)58.0*tan(phi)*tan(phi)) + + pow(tan(phi),(double)4.0)); + IV = nu * cos(phi); + + tmp = pow(cos(phi),(double)3.0); + tmp *= ((nu/rho) - tan(phi) * tan(phi)); + V = (nu/(double)6.0) * tmp; + + tmp = (double)5.0 - ((double)18.0 * tan(phi) * tan(phi)); + tmp += tan(phi)*tan(phi)*tan(phi)*tan(phi) + ((double)14.0 * etasq); + tmp -= ((double)58.0 * tan(phi) * tan(phi) * etasq); + tmp2 = cos(phi)*cos(phi)*cos(phi)*cos(phi)*cos(phi) * tmp; + VI = (nu / (double)120.0) * tmp2; + + *N = I + II*(lambda-lambda0)*(lambda-lambda0) + + III*pow((lambda-lambda0),(double)4.0) + + IIIA*pow((lambda-lambda0),(double)6.0); + + *E = E0 + IV*(lambda-lambda0) + V*pow((lambda-lambda0),(double)3.0) + + VI * pow((lambda-lambda0),(double)5.0); + + return; +} + + + +/* @func GPS_Math_Airy1830MLatLonToINGEN ************************************ +** +** Convert Modified Airy 1830 datum latitude and longitude to Irish +** National Grid Eastings and Northings +** +** @param [r] phi [double] modified Airy latitude (deg) +** @param [r] lambda [double] modified Airy longitude (deg) +** @param [w] E [double *] NG easting (metres) +** @param [w] N [double *] NG northing (metres) +** +** @return [void] +************************************************************************/ +void GPS_Math_Airy1830M_LatLonToINGEN(double phi, double lambda, double *E, + double *N) +{ + double N0 = 250000; + double E0 = 200000; + double F0 = 1.000035; + double phi0 = 53.5; + double lambda0 = -8.; + double a = 6377340.189; + double b = 6356034.447; + + GPS_Math_LatLon_To_EN(E,N,phi,lambda,N0,E0,phi0,lambda0,F0,a,b); + + return; +} + + + + +/* @func GPS_Math_Airy1830LatLonToNGEN ************************************** +** +** Convert Airy 1830 datum latitude and longitude to UK Ordnance Survey +** National Grid Eastings and Northings +** +** @param [r] phi [double] WGS84 latitude (deg) +** @param [r] lambda [double] WGS84 longitude (deg) +** @param [w] E [double *] NG easting (metres) +** @param [w] N [double *] NG northing (metres) +** +** @return [void] +************************************************************************/ +void GPS_Math_Airy1830LatLonToNGEN(double phi, double lambda, double *E, + double *N) +{ + double N0 = -100000; + double E0 = 400000; + double F0 = 0.9996012717; + double phi0 = 49.; + double lambda0 = -2.; + double a = 6377563.396; + double b = 6356256.910; + + GPS_Math_LatLon_To_EN(E,N,phi,lambda,N0,E0,phi0,lambda0,F0,a,b); + + return; +} + + + + +/* @func GPS_Math_EN_To_LatLon ************************************** +** +** Convert Eastings and Northings to latitude and longitude +** +** @param [w] E [double] NG easting (metres) +** @param [w] N [double] NG northing (metres) +** @param [r] phi [double *] Airy latitude (deg) +** @param [r] lambda [double *] Airy longitude (deg) +** @param [r] N0 [double] true northing origin (metres) +** @param [r] E0 [double] true easting origin (metres) +** @param [r] phi0 [double] true latitude origin (deg) +** @param [r] lambda0 [double] true longitude origin (deg) +** @param [r] F0 [double] scale factor on central meridian +** @param [r] a [double] semi-major axis (metres) +** @param [r] b [double] semi-minor axis (metres) +** +** @return [void] +************************************************************************/ +void GPS_Math_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double N0, double E0, + double phi0, double lambda0, + double F0, double a, double b) +{ + double esq; + double n; + double etasq; + double nu; + double rho; + double M; + double VII; + double VIII; + double IX; + double X; + double XI; + double XII; + double XIIA; + double phix; + double nphi=0.0; + + double tmp; + double tmp2; + double fdf; + double fde; + + phi0 = GPS_Math_Deg_To_Rad(phi0); + lambda0 = GPS_Math_Deg_To_Rad(lambda0); + + n = (a-b) / (a+b); + fdf = (double)5.0 / (double)4.0; + fde = ((double)15.0 / (double)8.0); + + esq = ((a*a)-(b*b)) / (a*a); + + + phix = ((N-N0)/(a*F0)) + phi0; + + tmp = (double)1.0 - (esq * sin(phix) * sin(phix)); + nu = a * F0 * pow(tmp,(double)-0.5); + rho = a * F0 * ((double)1.0 - esq) * pow(tmp,(double)-1.5); + etasq = (nu / rho) - (double)1.0; + + M = (double)-1e20; + + while(N-N0-M > (double)0.000001) + { + nphi = phix; + + tmp = (double)1.0 + n + (fdf * n * n) + (fdf * n * n * n); + tmp *= (nphi - phi0); + tmp2 = (double)3.0*n + (double)3.0*n*n + + ((double)21./(double)8.)*n*n*n; + tmp2 *= (sin(nphi-phi0) * cos(nphi+phi0)); + tmp -= tmp2; + + + tmp2 = ((fde*n*n) + (fde*n*n*n)) * sin((double)2.0 * (nphi-phi0)); + tmp2 *= cos((double)2.0 * (nphi+phi0)); + tmp += tmp2; + + tmp2 = ((double)35.0/(double)24.0) * n * n * n; + tmp2 *= sin((double)3.0 * (nphi-phi0)); + tmp2 *= cos((double)3.0 * (nphi+phi0)); + tmp -= tmp2; + + M = b * F0 * tmp; + + if(N-N0-M > (double)0.000001) + phix = ((N-N0-M)/(a*F0)) + nphi; + } + + + VII = tan(nphi) / ((double)2.0 * rho * nu); + + tmp = (double)5.0 + (double)3.0 * tan(nphi) * tan(nphi) + etasq; + tmp -= (double)9.0 * tan(nphi) * tan(nphi) * etasq; + VIII = (tan(nphi)*tmp) / ((double)24.0 * rho * nu*nu*nu); + + tmp = (double)61.0 + (double)90.0 * tan(nphi) * tan(nphi); + tmp += (double)45.0 * pow(tan(nphi),(double)4.0); + IX = tan(nphi) / ((double)720.0 * rho * pow(nu,(double)5.0)) * tmp; + + X = (double)1.0 / (cos(nphi) * nu); + + tmp = (nu / rho) + (double)2.0 * tan(nphi) * tan(nphi); + XI = ((double)1.0 / (cos(nphi) * (double)6.0 * nu*nu*nu)) * tmp; + + tmp = (double)5.0 + (double)28.0 * tan(nphi)*tan(nphi); + tmp += (double)24.0 * pow(tan(nphi),(double)4.0); + XII = ((double)1.0 / ((double)120.0 * pow(nu,(double)5.0) * cos(nphi))) + * tmp; + + tmp = (double)61.0 + (double)662.0 * tan(nphi) * tan(nphi); + tmp += (double)1320.0 * pow(tan(nphi),(double)4.0); + tmp += (double)720.0 * pow(tan(nphi),(double)6.0); + XIIA = ((double)1.0 / (cos(nphi) * (double)5040.0 * pow(nu,(double)7.0))) + * tmp; + + *phi = nphi - VII*pow((E-E0),(double)2.0) + VIII*pow((E-E0),(double)4.0) - + IX*pow((E-E0),(double)6.0); + + *lambda = lambda0 + X*(E-E0) - XI*pow((E-E0),(double)3.0) + + XII*pow((E-E0),(double)5.0) - XIIA*pow((E-E0),(double)7.0); + + *phi = GPS_Math_Rad_To_Deg(*phi); + *lambda = GPS_Math_Rad_To_Deg(*lambda); + + return; +} + + + + +/* @func GPS_Math_NGENToAiry1830LatLon ************************************** +** +** Convert to UK Ordnance Survey National Grid Eastings and Northings to +** Airy 1830 datum latitude and longitude +** +** @param [r] E [double] NG easting (metres) +** @param [r] N [double] NG northing (metres) +** @param [w] phi [double *] Airy latitude (deg) +** @param [w] lambda [double *] Airy longitude (deg) +** +** @return [void] +************************************************************************/ +void GPS_Math_NGENToAiry1830LatLon(double E, double N, double *phi, + double *lambda) +{ + double N0 = -100000; + double E0 = 400000; + double F0 = 0.9996012717; + double phi0 = 49.; + double lambda0 = -2.; + double a = 6377563.396; + double b = 6356256.910; + + GPS_Math_EN_To_LatLon(E,N,phi,lambda,N0,E0,phi0,lambda0,F0,a,b); + + return; +} + + + +/* @func GPS_Math_INGENToAiry1830MLatLon ************************************** +** +** Convert Irish National Grid Eastings and Northings to modified +** Airy 1830 datum latitude and longitude +** +** @param [r] E [double] ING easting (metres) +** @param [r] N [double] ING northing (metres) +** @param [w] phi [double *] modified Airy latitude (deg) +** @param [w] lambda [double *] modified Airy longitude (deg) +** +** @return [void] +************************************************************************/ +void GPS_Math_INGENToAiry1830MLatLon(double E, double N, double *phi, + double *lambda) +{ + double N0 = 250000; + double E0 = 200000; + double F0 = 1.000035; + double phi0 = 53.5; + double lambda0 = -8.; + double a = 6377340.189; + double b = 6356034.447; + + GPS_Math_EN_To_LatLon(E,N,phi,lambda,N0,E0,phi0,lambda0,F0,a,b); + + return; +} + + + +/* @func GPS_Math_EN_To_UKOSNG_Map ************************************* +** +** Convert Airy 1830 eastings and northings to Ordnance Survey map +** two letter code plus modified eastings and northings +** +** @param [r] E [double] NG easting (metres) +** @param [r] N [double] NG northing (metres) +** @param [w] mE [double *] modified easting (metres) +** @param [w] mN [double *] modified northing (metres) +** @param [w] map [char *] map code +** +** @return [int32] success +************************************************************************/ +int32 GPS_Math_EN_To_UKOSNG_Map(double E, double N, double *mE, + double *mN, char *map) +{ + int32 t; + int32 idx; + + if(E>=(double)700000. || E<(double)0.0 || N<(double)0.0 || + N>=(double)1300000.0) + return 0; + + idx = ((int32)N/100000)*7 + (int32)E/100000; + (void) strcpy(map,UKNG[idx]); + + t = ((int32)E / 100000) * 100000; + *mE = E - (double)t; + + t = ((int32)N / 100000) * 100000; + *mN = N - (double)t; + + return 1; +} + + + +/* @func GPS_Math_UKOSNG_Map_To_EN ************************************* +** +** Convert Ordnance Survey map eastings and northings plus +** two letter code to Airy 1830 eastings and northings +** +** @param [w] map [char *] map code +** @param [r] mapE [double] easting (metres) +** @param [r] mapN [double] northing (metres) +** @param [w] E [double *] full Airy easting (metres) +** @param [w] N [double *] full Airy northing (metres) + +** +** @return [int32] success +************************************************************************/ +int32 GPS_Math_UKOSNG_Map_To_EN(char *map, double mapE, double mapN, double *E, + double *N) +{ + int32 t; + int32 idx; + + if(mapE>=(double)100000.0 || mapE<(double)0.0 || mapN<(double)0.0 || + mapN>(double)100000.0) + return 0; + + idx=0; + while(*UKNG[idx]) + { + if(!strcmp(UKNG[idx],map)) break; + ++idx; + } + if(!*UKNG[idx]) + return 0; + + + t = (idx / 7) * 100000; + *N = mapN + (double)t; + + t = (idx % 7) * 100000; + *E = mapE + (double)t; + + return 1; +} + + + +/* @func GPS_Math_Molodensky ******************************************* +** +** Transform one datum to another +** +** @param [r] Sphi [double] source latitude (deg) +** @param [r] Slam [double] source longitude (deg) +** @param [r] SH [double] source height (metres) +** @param [r] Sa [double] source semi-major axis (metres) +** @param [r] Sif [double] source inverse flattening +** @param [w] Dphi [double *] dest latitude (deg) +** @param [w] Dlam [double *] dest longitude (deg) +** @param [w] DH [double *] dest height (metres) +** @param [r] Da [double] dest semi-major axis (metres) +** @param [r] Dif [double] dest inverse flattening +** @param [r] dx [double] dx +** @param [r] dy [double] dy +** @param [r] dz [double] dz +** +** @return [void] +************************************************************************/ +void GPS_Math_Molodensky(double Sphi, double Slam, double SH, double Sa, + double Sif, double *Dphi, double *Dlam, + double *DH, double Da, double Dif, double dx, + double dy, double dz) +{ + double Sf; + double Df; + double esq; + double bda; + double da; + double df; + double N; + double M; + double tmp; + double tmp2; + double dphi; + double dlambda; + double dheight; + double phis; + double phic; + double lams; + double lamc; + + Sf = (double)1.0 / Sif; + Df = (double)1.0 / Dif; + + esq = (double)2.0*Sf - pow(Sf,(double)2.0); + bda = (double)1.0 - Sf; + Sphi = GPS_Math_Deg_To_Rad(Sphi); + Slam = GPS_Math_Deg_To_Rad(Slam); + + da = Da - Sa; + df = Df - Sf; + + phis = sin(Sphi); + phic = cos(Sphi); + lams = sin(Slam); + lamc = cos(Slam); + + N = Sa / sqrt((double)1.0 - esq*pow(phis,(double)2.0)); + + tmp = ((double)1.0-esq) /pow(((double)1.0-esq*pow(phis,(double)2.0)),1.5); + M = Sa * tmp; + + tmp = df * ((M/bda)+N*bda) * phis * phic; + tmp2 = da * N * esq * phis * phic / Sa; + tmp2 += ((-dx*phis*lamc-dy*phis*lams) + dz*phic); + dphi = (tmp2 + tmp) / (M + SH); + + dlambda = (-dx*lams+dy*lamc) / ((N+SH)*phic); + + dheight = dx*phic*lamc + dy*phic*lams + dz*phis - da*(Sa/N) + + df*bda*N*phis*phis; + + *Dphi = Sphi + dphi; + *Dlam = Slam + dlambda; + *DH = SH + dheight; + + *Dphi = GPS_Math_Rad_To_Deg(*Dphi); + *Dlam = GPS_Math_Rad_To_Deg(*Dlam); + + return; +} + + + +/* @func GPS_Math_Known_Datum_To_WGS84_M ********************************** +** +** Transform datum to WGS84 using Molodensky +** +** @param [r] Sphi [double] source latitude (deg) +** @param [r] Slam [double] source longitude (deg) +** @param [r] SH [double] source height (metres) +** @param [w] Dphi [double *] dest latitude (deg) +** @param [w] Dlam [double *] dest longitude (deg) +** @param [w] DH [double *] dest height (metres) +** @param [r] n [int32] datum number from GPS_Datum structure +** +** @return [void] +************************************************************************/ +void GPS_Math_Known_Datum_To_WGS84_M(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, double *DH, + int32 n) +{ + double Sa; + double Sif; + double Da; + double Dif; + double x; + double y; + double z; + int32 idx; + + Da = (double) 6378137.0; + Dif = (double) 298.257223563; + + idx = GPS_Datum[n].ellipse; + Sa = GPS_Ellipse[idx].a; + Sif = GPS_Ellipse[idx].invf; + x = GPS_Datum[n].dx; + y = GPS_Datum[n].dy; + z = GPS_Datum[n].dz; + + GPS_Math_Molodensky(Sphi,Slam,SH,Sa,Sif,Dphi,Dlam,DH,Da,Dif,x,y,z); + + return; +} + + + +/* @func GPS_Math_WGS84_To_Known_Datum_M ******************************** +** +** Transform WGS84 to other datum using Molodensky +** +** @param [r] Sphi [double] source latitude (deg) +** @param [r] Slam [double] source longitude (deg) +** @param [r] SH [double] source height (metres) +** @param [w] Dphi [double *] dest latitude (deg) +** @param [w] Dlam [double *] dest longitude (deg) +** @param [w] DH [double *] dest height (metres) +** @param [r] n [int32] datum number from GPS_Datum structure +** +** @return [void] +************************************************************************/ +void GPS_Math_WGS84_To_Known_Datum_M(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, double *DH, + int32 n) +{ + double Sa; + double Sif; + double Da; + double Dif; + double x; + double y; + double z; + int32 idx; + + Sa = (double) 6378137.0; + Sif = (double) 298.257223563; + + idx = GPS_Datum[n].ellipse; + Da = GPS_Ellipse[idx].a; + Dif = GPS_Ellipse[idx].invf; + x = -GPS_Datum[n].dx; + y = -GPS_Datum[n].dy; + z = -GPS_Datum[n].dz; + + GPS_Math_Molodensky(Sphi,Slam,SH,Sa,Sif,Dphi,Dlam,DH,Da,Dif,x,y,z); + + return; +} + + + +/* @func GPS_Math_Known_Datum_To_WGS84_C ********************************** +** +** Transform datum to WGS84 using Cartesian coordinates +** +** @param [r] Sphi [double] source latitude (deg) +** @param [r] Slam [double] source longitude (deg) +** @param [r] SH [double] source height (metres) +** @param [w] Dphi [double *] dest latitude (deg) +** @param [w] Dlam [double *] dest longitude (deg) +** @param [w] DH [double *] dest height (metres) +** @param [r] n [int32] datum number from GPS_Datum structure +** +** @return [void] +************************************************************************/ +void GPS_Math_Known_Datum_To_WGS84_C(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, double *DH, + int32 n) +{ + double Sa; + double Sif; + double Sb; + double Da; + double Dif; + double Db; + double x; + double y; + double z; + int32 idx; + double sx; + double sy; + double sz; + + Da = (double) 6378137.0; + Dif = (double) 298.257223563; + Db = Da - (Da / Dif); + + idx = GPS_Datum[n].ellipse; + Sa = GPS_Ellipse[idx].a; + Sif = GPS_Ellipse[idx].invf; + Sb = Sa - (Sa / Sif); + + x = GPS_Datum[n].dx; + y = GPS_Datum[n].dy; + z = GPS_Datum[n].dz; + + GPS_Math_LatLonH_To_XYZ(Sphi,Slam,SH,&sx,&sy,&sz,Sa,Sb); + sx += x; + sy += y; + sz += z; + + GPS_Math_XYZ_To_LatLonH(Dphi,Dlam,DH,sx,sy,sz,Da,Db); + + return; +} + + + +/* @func GPS_Math_WGS84_To_Known_Datum_C ******************************** +** +** Transform WGS84 to other datum using Cartesian coordinates +** +** @param [r] Sphi [double] source latitude (deg) +** @param [r] Slam [double] source longitude (deg) +** @param [r] SH [double] source height (metres) +** @param [w] Dphi [double *] dest latitude (deg) +** @param [w] Dlam [double *] dest longitude (deg) +** @param [w] DH [double *] dest height (metres) +** @param [r] n [int32] datum number from GPS_Datum structure +** +** @return [void] +************************************************************************/ +void GPS_Math_WGS84_To_Known_Datum_C(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, double *DH, + int32 n) +{ + double Sa; + double Sif; + double Da; + double Dif; + double x; + double y; + double z; + int32 idx; + double Sb; + double Db; + double dx; + double dy; + double dz; + + Sa = (double) 6378137.0; + Sif = (double) 298.257223563; + Sb = Sa - (Sa / Sif); + + idx = GPS_Datum[n].ellipse; + Da = GPS_Ellipse[idx].a; + Dif = GPS_Ellipse[idx].invf; + Db = Da - (Da / Dif); + + x = -GPS_Datum[n].dx; + y = -GPS_Datum[n].dy; + z = -GPS_Datum[n].dz; + + GPS_Math_LatLonH_To_XYZ(Sphi,Slam,SH,&dx,&dy,&dz,Sa,Sb); + dx += x; + dy += y; + dz += z; + + GPS_Math_XYZ_To_LatLonH(Dphi,Dlam,DH,dx,dy,dz,Da,Db); + + return; +} + + + +/* @func GPS_Math_Known_Datum_To_Known_Datum_M ************************* +** +** Transform WGS84 to other datum using Molodensky +** +** @param [r] Sphi [double] source latitude (deg) +** @param [r] Slam [double] source longitude (deg) +** @param [r] SH [double] source height (metres) +** @param [w] Dphi [double *] dest latitude (deg) +** @param [w] Dlam [double *] dest longitude (deg) +** @param [w] DH [double *] dest height (metres) +** @param [r] n1 [int32] source datum number from GPS_Datum structure +** @param [r] n2 [int32] dest datum number from GPS_Datum structure +** +** @return [void] +************************************************************************/ +void GPS_Math_Known_Datum_To_Known_Datum_M(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, + double *DH, int32 n1, int32 n2) +{ + double Sa; + double Sif; + double Da; + double Dif; + double x1; + double y1; + double z1; + double x2; + double y2; + double z2; + double x; + double y; + double z; + + int32 idx1; + int32 idx2; + + + idx1 = GPS_Datum[n1].ellipse; + Sa = GPS_Ellipse[idx1].a; + Sif = GPS_Ellipse[idx1].invf; + x1 = GPS_Datum[n1].dx; + y1 = GPS_Datum[n1].dy; + z1 = GPS_Datum[n1].dz; + + idx2 = GPS_Datum[n2].ellipse; + Da = GPS_Ellipse[idx2].a; + Dif = GPS_Ellipse[idx2].invf; + x2 = GPS_Datum[n2].dx; + y2 = GPS_Datum[n2].dy; + z2 = GPS_Datum[n2].dz; + + x = -(x2-x1); + y = -(y2-y1); + z = -(z2-z1); + + GPS_Math_Molodensky(Sphi,Slam,SH,Sa,Sif,Dphi,Dlam,DH,Da,Dif,x,y,z); + + return; +} + + + +/* @func GPS_Math_Known_Datum_To_Known_Datum_C ************************* +** +** Transform known datum to other datum using Cartesian coordinates +** +** @param [r] Sphi [double] source latitude (deg) +** @param [r] Slam [double] source longitude (deg) +** @param [r] SH [double] source height (metres) +** @param [w] Dphi [double *] dest latitude (deg) +** @param [w] Dlam [double *] dest longitude (deg) +** @param [w] DH [double *] dest height (metres) +** @param [r] n1 [int32] source datum number from GPS_Datum structure +** @param [r] n2 [int32] dest datum number from GPS_Datum structure +** +** @return [void] +************************************************************************/ +void GPS_Math_Known_Datum_To_Known_Datum_C(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, + double *DH, int32 n1, int32 n2) +{ + double Sa; + double Sif; + double Da; + double Dif; + double x1; + double y1; + double z1; + double x2; + double y2; + double z2; + + int32 idx1; + int32 idx2; + + double Sb; + double Db; + double dx; + double dy; + double dz; + + idx1 = GPS_Datum[n1].ellipse; + Sa = GPS_Ellipse[idx1].a; + Sif = GPS_Ellipse[idx1].invf; + Sb = Sa - (Sa / Sif); + + x1 = GPS_Datum[n1].dx; + y1 = GPS_Datum[n1].dy; + z1 = GPS_Datum[n1].dz; + + idx2 = GPS_Datum[n2].ellipse; + Da = GPS_Ellipse[idx2].a; + Dif = GPS_Ellipse[idx2].invf; + Db = Da - (Da / Dif); + + x2 = GPS_Datum[n2].dx; + y2 = GPS_Datum[n2].dy; + z2 = GPS_Datum[n2].dz; + + GPS_Math_LatLonH_To_XYZ(Sphi,Slam,SH,&dx,&dy,&dz,Sa,Sb); + dx += -(x2-x1); + dy += -(y2-y1); + dz += -(z2-z1); + + GPS_Math_XYZ_To_LatLonH(Dphi,Dlam,DH,dx,dy,dz,Da,Db); + + return; +} + + + +/* @func GPS_Math_WGS84_To_UKOSMap_M *********************************** +** +** Convert WGS84 lat/lon to Ordnance survey map code and easting and +** northing. Uses Molodensky +** +** @param [r] lat [double] WGS84 latitude (deg) +** @param [r] lon [double] WGS84 longitude (deg) +** @param [w] mE [double *] map easting (metres) +** @param [w] mN [double *] map northing (metres) +** @param [w] map [char *] map two letter code +** +** @return [int32] success +************************************************************************/ +int32 GPS_Math_WGS84_To_UKOSMap_M(double lat, double lon, double *mE, + double *mN, char *map) +{ + double alat; + double alon; + double aht; + double aE; + double aN; + + + GPS_Math_WGS84_To_Known_Datum_M(lat,lon,30,&alat,&alon,&aht,86); + + GPS_Math_Airy1830LatLonToNGEN(alat,alon,&aE,&aN); + + if(!GPS_Math_EN_To_UKOSNG_Map(aE,aN,mE,mN,map)) + return 0; + + return 1; +} + + + +/* @func GPS_Math_UKOSMap_To_WGS84_M *********************************** +** +** Transform UK Ordnance survey map position to WGS84 lat/lon +** Uses Molodensky transformation +** +** @param [r] map [char *] map two letter code +** @param [r] mE [double] map easting (metres) +** @param [r] mN [double] map northing (metres) +** @param [w] lat [double *] WGS84 latitude (deg) +** @param [w] lon [double *] WGS84 longitude (deg) +** +** @return [int32] success +************************************************************************/ +int32 GPS_Math_UKOSMap_To_WGS84_M(char *map, double mE, double mN, + double *lat, double *lon) +{ + double E; + double N; + double alat; + double alon; + double ht; + + if(!GPS_Math_UKOSNG_Map_To_EN(map,mE,mN,&E,&N)) + return 0; + + GPS_Math_NGENToAiry1830LatLon(E,N,&alat,&alon); + + GPS_Math_Known_Datum_To_WGS84_M(alat,alon,0,lat,lon,&ht,78); + + return 1; +} + + + +/* @func GPS_Math_WGS84_To_UKOSMap_C *********************************** +** +** Convert WGS84 lat/lon to Ordnance survey map code and easting and +** northing. Uses cartesian transformation +** +** @param [r] lat [double] WGS84 latitude (deg) +** @param [r] lon [double] WGS84 longitude (deg) +** @param [w] mE [double *] map easting (metres) +** @param [w] mN [double *] map northing (metres) +** @param [w] map [char *] map two letter code +** +** @return [int32] success +************************************************************************/ +int32 GPS_Math_WGS84_To_UKOSMap_C(double lat, double lon, double *mE, + double *mN, char *map) +{ + double alat; + double alon; + double aht; + double aE; + double aN; + + + GPS_Math_WGS84_To_Known_Datum_C(lat,lon,30,&alat,&alon,&aht,86); + + GPS_Math_Airy1830LatLonToNGEN(alat,alon,&aE,&aN); + + if(!GPS_Math_EN_To_UKOSNG_Map(aE,aN,mE,mN,map)) + return 0; + + return 1; +} + + + +/* @func GPS_Math_UKOSMap_To_WGS84_C *********************************** +** +** Transform UK Ordnance survey map position to WGS84 lat/lon +** Uses cartesian transformation +** +** @param [r] map [char *] map two letter code +** @param [r] mE [double] map easting (metres) +** @param [r] mN [double] map northing (metres) +** @param [w] lat [double *] WGS84 latitude (deg) +** @param [w] lon [double *] WGS84 longitude (deg) +** +** @return [int32] success +************************************************************************/ +int32 GPS_Math_UKOSMap_To_WGS84_C(char *map, double mE, double mN, + double *lat, double *lon) +{ + double E; + double N; + double alat; + double alon; + double ht; + + if(!GPS_Math_UKOSNG_Map_To_EN(map,mE,mN,&E,&N)) + return 0; + + GPS_Math_NGENToAiry1830LatLon(E,N,&alat,&alon); + + GPS_Math_Known_Datum_To_WGS84_C(alat,alon,0,lat,lon,&ht,78); + + return 1; +} + + +/* @funcstatic GPS_Math_LatLon_To_UTM_Param ***************************** +** +** Transform NAD33 +** +** @param [r] lat [double] NAD latitude (deg) +** @param [r] lon [double] NAD longitude (deg) +** @param [w] zone [int32 *] zone number +** @param [w] zc [char *] zone character +** @param [w] Mc [double *] central meridian +** @param [w] E0 [double *] false easting +** @param [w] N0 [double *] false northing +** @param [w] F0 [double *] scale factor +** +** @return [int32] success +************************************************************************/ +static int32 GPS_Math_LatLon_To_UTM_Param(double lat, double lon, int32 *zone, + char *zc, double *Mc, double *E0, + double *N0, double *F0) +{ + int32 ilon; + int32 ilat; + int32 psign; + int32 lsign; + + if(lat >= (double)84.0 || lat < (double)-80.0) + return 0; + + psign = lsign = 0; + if(lon < (double)0.0) + lsign=1; + if(lat < (double)0.0) + psign=1; + + ilon = abs((int32)lon); + ilat = abs((int32)lat); + + if(!lsign) + { + *zone = 31 + (ilon / 6); + *Mc = (double)((ilon / 6) * 6 + 3); + } + else + { + *zone = 30 - (ilon / 6); + *Mc = -(double)((ilon / 6) * 6 + 3); + } + + if(!psign) + { + *zc = 'N' + ilat / 8; + if(*zc > 'N') ++*zc; + } + else + { + *zc = 'M' - (ilat / 8); + if(*zc <= 'I') --*zc; + } + + + if(lat>=(double)56.0 && lat<(double)64.0 && lon>=(double)3.0 && + lon<(double)12.0) + { + *zone = 32; + *zc = 'V'; + *Mc = (double)9.0; + } + + if(*zc=='X' && lon>=(double)0.0 && lon<(double)42.0) + { + if(lon<(double)9.0) + { + *zone = 31; + *Mc = (double)3.0; + } + else if(lon<(double)21.0) + { + *zone = 33; + *Mc = (double)15.0; + } + else if(lon<(double)33.0) + { + *zone = 35; + *Mc = (double)27.0; + } + else + { + *zone = 37; + *Mc = (double)39.0; + } + } + + if(!psign) + *N0 = (double)0.0; + else + *N0 = (double)10000000; + + *E0 = (double)500000; + *F0 = (double)0.9996; + + return 1; +} + + + +/* @func GPS_Math_NAD83_To_UTM_EN ************************************** +** +** Transform NAD33 lat/lon to UTM zone, easting and northing +** +** @param [r] lat [double] NAD latitude (deg) +** @param [r] lon [double] NAD longitude (deg) +** @param [w] E [double *] easting (metres) +** @param [w] N [double *] northing (metres) +** @param [w] zone [int32 *] zone number +** @param [w] zc [char *] zone character +** +** @return [int32] success +************************************************************************/ +int32 GPS_Math_NAD83_To_UTM_EN(double lat, double lon, double *E, + double *N, int32 *zone, char *zc) +{ + double phi0; + double lambda0; + double N0; + double E0; + double F0; + double a; + double b; + + if(!GPS_Math_LatLon_To_UTM_Param(lat,lon,zone,zc,&lambda0,&E0, + &N0,&F0)) + return 0; + + phi0 = (double)0.0; + + a = (double) GPS_Ellipse[21].a; + b = a - (a/GPS_Ellipse[21].invf); + + GPS_Math_LatLon_To_EN(E,N,lat,lon,N0,E0,phi0,lambda0,F0,a,b); + + return 1; +} + + + +/* @func GPS_Math_WGS84_To_UTM_EN ************************************** +** +** Transform WGS84 lat/lon to UTM zone, easting and northing +** +** @param [r] lat [double] WGS84 latitude (deg) +** @param [r] lon [double] WGS84 longitude (deg) +** @param [w] E [double *] easting (metres) +** @param [w] N [double *] northing (metres) +** @param [w] zone [int32 *] zone number +** @param [w] zc [char *] zone character +** +** @return [int32] success +************************************************************************/ +int32 GPS_Math_WGS84_To_UTM_EN(double lat, double lon, double *E, + double *N, int32 *zone, char *zc) +{ + double phi; + double lambda; + double H; + + GPS_Math_WGS84_To_Known_Datum_M(lat,lon,0,&phi,&lambda,&H,77); + if(!GPS_Math_NAD83_To_UTM_EN(phi,lambda,E,N,zone,zc)) + return 0; + + return 1; +} + + + +/* @funcstatic GPS_Math_UTM_Param_To_Mc ******************************** +** +** Convert UTM zone and zone character to central meridian value. +** Also return false eastings, northings and scale factor +** +** @param [w] zone [int32] zone number +** @param [w] zc [char] zone character +** @param [w] Mc [double *] central meridian +** @param [w] E0 [double *] false easting +** @param [w] N0 [double *] false northing +** @param [w] F0 [double *] scale factor +** +** @return [int32] success +************************************************************************/ +static int32 GPS_Math_UTM_Param_To_Mc(int32 zone, char zc, double *Mc, + double *E0, double *N0, double *F0) +{ + + if(zone>60 || zone<0 || zc<'C' || zc>'X') + return 0; + + if(zone > 30) + *Mc = (double)((zone-31)*6) + (double)3.0; + else + *Mc = (double) -(((30-zone)*6)+3); + + if(zone==32 && zc=='V') + *Mc = (double)9.0; + + if(zone==31 && zc=='X') + *Mc = (double)3.0; + if(zone==33 && zc=='X') + *Mc = (double)15.0; + if(zone==35 && zc=='X') + *Mc = (double)27.0; + if(zone==37 && zc=='X') + *Mc = (double)39.0; + + if(zc>'M') + *N0 = (double)0.0; + else + *N0 = (double)10000000; + + *E0 = (double)500000; + *F0 = (double)0.9996; + + return 1; +} + + + +/* @func GPS_Math_UTM_EN_To_NAD83 ************************************** +** +** Transform UTM zone, easting and northing to NAD83 lat/lon +** +** @param [r] lat [double *] NAD latitude (deg) +** @param [r] lon [double *] NAD longitude (deg) +** @param [w] E [double] easting (metres) +** @param [w] N [double] northing (metres) +** @param [w] zone [int32] zone number +** @param [w] zc [char] zone character +** +** @return [int32] success +************************************************************************/ +int32 GPS_Math_UTM_EN_To_NAD83(double *lat, double *lon, double E, + double N, int32 zone, char zc) +{ + double phi0; + double lambda0; + double N0; + double E0; + double F0; + double a; + double b; + + if(!GPS_Math_UTM_Param_To_Mc(zone,zc,&lambda0,&E0,&N0,&F0)) + return 0; + + phi0 = (double)0.0; + + a = (double) GPS_Ellipse[21].a; + b = a - (a/GPS_Ellipse[21].invf); + + GPS_Math_EN_To_LatLon(E,N,lat,lon,N0,E0,phi0,lambda0,F0,a,b); + + return 1; +} + + + +/* @func GPS_Math_UTM_EN_To_WGS84 ************************************** +** +** Transform UTM zone, easting and northing to WGS84 lat/lon +** +** @param [w] lat [double *] WGS84 latitude (deg) +** @param [r] lon [double *] WGS84 longitude (deg) +** @param [w] E [double] easting (metres) +** @param [w] N [double] northing (metres) +** @param [w] zone [int32] zone number +** @param [w] zc [char] zone character +** +** @return [int32] success +************************************************************************/ +int32 GPS_Math_UTM_EN_To_WGS84(double *lat, double *lon, double E, + double N, int32 zone, char zc) +{ + double phi; + double lambda; + double H; + + if(!GPS_Math_UTM_EN_To_NAD83(&phi,&lambda,E,N,zone,zc)) + return 0; + + + GPS_Math_Known_Datum_To_WGS84_M(phi,lambda,0,lat,lon,&H,77); + + return 1; +} diff --git a/jeeps/gpsmath.h b/jeeps/gpsmath.h new file mode 100644 index 000000000..4e2249f08 --- /dev/null +++ b/jeeps/gpsmath.h @@ -0,0 +1,123 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsmath_h +#define gpsmath_h + + +#include "gps.h" + +#define GPS_PI 3.141592653589 +#define GPS_FLTMIN 1.75494351E-38 +#define GPS_FLTMAX 3.402823466E+38 + + +double GPS_Math_Deg_To_Rad(double v); +double GPS_Math_Rad_To_Deg(double v); + +double GPS_Math_Metres_To_Feet(double v); +double GPS_Math_Feet_To_Metres(double v); + +int32 GPS_Math_Deg_To_Semi(double v); +double GPS_Math_Semi_To_Deg(int32 v); + +time_t GPS_Math_Utime_To_Gtime(time_t v); +time_t GPS_Math_Gtime_To_Utime(time_t v); + +void GPS_Math_Deg_To_DegMin(double v, int32 *d, double *m); +void GPS_Math_DegMin_To_Deg(int32 d, double m, double *deg); +void GPS_Math_Deg_To_DegMinSec(double v, int32 *d, int32 *m, double *s); +void GPS_Math_DegMinSec_To_Deg(int32 d, int32 m, double s, double *deg); + + +void GPS_Math_Airy1830LatLonToNGEN(double phi, double lambda, double *E, + double *N); +void GPS_Math_Airy1830M_LatLonToINGEN(double phi, double lambda, double *E, + double *N); +int32 GPS_Math_EN_To_UKOSNG_Map(double E, double N, double *mE, + double *mN, char *map); +int32 GPS_Math_UKOSNG_Map_To_EN(char *map, double mapE, double mapN, + double *E, double *N); + +void GPS_Math_LatLonH_To_XYZ(double phi, double lambda, double H, + double *x, double *y, double *z, + double a, double b); +void GPS_Math_XYZ_To_LatLonH(double *phi, double *lambda, double *H, + double x, double y, double z, + double a, double b); + +void GPS_Math_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double N0, double E0, + double phi0, double lambda0, + double F0, double a, double b); +void GPS_Math_LatLon_To_EN(double *E, double *N, double phi, + double lambda, double N0, double E0, + double phi0, double lambda0, + double F0, double a, double b); + +void GPS_Math_NGENToAiry1830LatLon(double E, double N, double *phi, + double *lambda); +void GPS_Math_INGENToAiry1830MLatLon(double E, double N, double *phi, + double *lambda); + + +void GPS_Math_Airy1830LatLonH_To_XYZ(double phi, double lambda, double H, + double *x, double *y, double *z); +void GPS_Math_WGS84LatLonH_To_XYZ(double phi, double lambda, double H, + double *x, double *y, double *z); +void GPS_Math_XYZ_To_Airy1830LatLonH(double *phi, double *lambda, double *H, + double x, double y, double z); +void GPS_Math_XYZ_To_WGS84LatLonH(double *phi, double *lambda, double *H, + double x, double y, double z); + +void GPS_Math_Molodensky(double Sphi, double Slam, double SH, double Sa, + double Sif, double *Dphi, double *Dlam, + double *DH, double Da, double Dif, double dx, + double dy, double dz); +void GPS_Math_Known_Datum_To_WGS84_M(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, double *DH, + int32 n); +void GPS_Math_WGS84_To_Known_Datum_M(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, double *DH, + int32 n); +void GPS_Math_Known_Datum_To_WGS84_C(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, double *DH, + int32 n); +void GPS_Math_WGS84_To_Known_Datum_C(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, double *DH, + int32 n); + +void GPS_Math_Known_Datum_To_Known_Datum_M(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, + double *DH, int32 n1, int32 n2); +void GPS_Math_Known_Datum_To_Known_Datum_C(double Sphi, double Slam, double SH, + double *Dphi, double *Dlam, + double *DH, int32 n1, int32 n2); + +int32 GPS_Math_WGS84_To_UKOSMap_M(double lat, double lon, double *mE, + double *mN, char *map); +int32 GPS_Math_UKOSMap_To_WGS84_M(char *map, double mE, double mN, + double *lat, double *lon); +int32 GPS_Math_WGS84_To_UKOSMap_C(double lat, double lon, double *mE, + double *mN, char *map); +int32 GPS_Math_UKOSMap_To_WGS84_C(char *map, double mE, double mN, + double *lat, double *lon); + + +int32 GPS_Math_NAD83_To_UTM_EN(double lat, double lon, double *E, + double *N, int32 *zone, char *zc); +int32 GPS_Math_WGS84_To_UTM_EN(double lat, double lon, double *E, + double *N, int32 *zone, char *zc); + +int32 GPS_Math_UTM_EN_To_WGS84(double *lat, double *lon, double E, + double N, int32 zone, char zc); +int32 GPS_Math_UTM_EN_To_NAD83(double *lat, double *lon, double E, + double N, int32 zone, char zc); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsmem.c b/jeeps/gpsmem.c new file mode 100644 index 000000000..b351a0a43 --- /dev/null +++ b/jeeps/gpsmem.c @@ -0,0 +1,1484 @@ +/******************************************************************** +** @source JEEPS constructor and deconstructor functions +** +** @author Copyright (C) 1999,2000 Alan Bleasby +** @version 1.0 +** @modified December 28th 1999 Alan Bleasby. First version +** @modified June 29th 2000 Alan Bleasby. NMEA additions +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include "garminusb.h" +#include +#include +#include +#include + +/* @func GPS_Packet_New *********************************************** +** +** Packet constructor +** +** @return [GPS_PPacket] virgin packet +**********************************************************************/ + +GPS_PPacket GPS_Packet_New(void) +{ + GPS_PPacket ret; + int hdr_size = gps_is_usb ? sizeof(garmin_usb_packet) : sizeof(GPS_OPacket) ; + if(!(ret=(GPS_PPacket )malloc(hdr_size))) + + { + perror("malloc"); + fprintf(stderr,"GPS_Packet_New: Insufficient memory"); + fflush(stderr); + return NULL; + } + if(!(ret->data = (UC *)malloc(MAX_GPS_PACKET_SIZE*sizeof(UC)))) + { + perror("malloc"); + fprintf(stderr,"GPS_Packet_New: Insufficient data memory"); + fflush(stderr); + return NULL; + } + + ret->dle = ret->edle = DLE; + ret->etx = ETX; + + return ret; +} + + + +/* @func GPS_Packet_Del *********************************************** +** +** Packet destructor +** +** @param [w] thys [GPS_PPacket *] packet to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Packet_Del(GPS_PPacket *thys) +{ + free((void *)(*thys)->data); + free((void *)*thys); + + return; +} + + + +/* @func GPS_Pvt_New *********************************************** +** +** Pvt constructor +** +** @return [GPS_PPvt_Data] virgin pvt +**********************************************************************/ + +GPS_PPvt_Data GPS_Pvt_New(void) +{ + GPS_PPvt_Data ret; + + if(!(ret=(GPS_PPvt_Data)malloc(sizeof(GPS_OPvt_Data)))) + { + perror("malloc"); + fprintf(stderr,"GPS_Pvt_New: Insufficient memory"); + fflush(stderr); + return NULL; + } + + return ret; +} + + + +/* @func GPS_Pvt_Del *********************************************** +** +** Pvt destructor +** +** @param [w] thys [GPS_PPvt_Data *] pvt to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Pvt_Del(GPS_PPvt_Data *thys) +{ + free((void *)*thys); + + return; +} + + + +/* @func GPS_Almanac_New *********************************************** +** +** Almanac constructor +** +** @return [GPS_PAlmanac] virgin almanac +**********************************************************************/ + +GPS_PAlmanac GPS_Almanac_New(void) +{ + GPS_PAlmanac ret; + + if(!(ret=(GPS_PAlmanac)malloc(sizeof(GPS_OAlmanac)))) + { + perror("malloc"); + fprintf(stderr,"GPS_Almanac_New: Insufficient memory"); + fflush(stderr); + return NULL; + } + + ret->svid=0xff; + ret->wn = -1; + ret->hlth=0xff; + + return ret; +} + + + +/* @func GPS_Almanac_Del *********************************************** +** +** Almanac destructor +** +** @param [w] thys [GPS_PAlmanac *] almanac to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Almanac_Del(GPS_PAlmanac *thys) +{ + free((void *)*thys); + + return; +} + + + +/* @func GPS_Track_New *********************************************** +** +** Track constructor +** +** @return [GPS_PTrack] virgin track +**********************************************************************/ + +GPS_PTrack GPS_Track_New(void) +{ + GPS_PTrack ret; + + if(!(ret=(GPS_PTrack)calloc(1,sizeof(GPS_OTrack)))) + { + perror("malloc"); + fprintf(stderr,"GPS_Track_New: Insufficient memory"); + fflush(stderr); + return NULL; + } + + return ret; +} + + + +/* @func GPS_Track_Del *********************************************** +** +** Track destructor +** +** @param [w] thys [GPS_PTrack *] track to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Track_Del(GPS_PTrack *thys) +{ + free((void *)*thys); + + return; +} + + + +/* @func GPS_Way_New *********************************************** +** +** Waypoint constructor +** +** @return [GPS_PWay] virgin waypoint +**********************************************************************/ + +GPS_PWay GPS_Way_New(void) +{ + GPS_PWay ret; + int32 i; + + if(!(ret=(GPS_PWay)xcalloc(sizeof(GPS_OWay),1))) + { + perror("malloc"); + fprintf(stderr,"GPS_Way_New: Insufficient memory"); + fflush(stderr); + return NULL; + } + + /* + * It turns out that the Way struct, initialized with zeros (not the + * random stuff that we got with malloc, but REALLY initialized with + * zeros from the calloc above actually does use C strings and it's + * up to the various way_blah_send functions to zero/string pad things + * as it goes. So neutralize this. + */ +#if 0 + + /* + * Mark all as "unused". These appear in the same order as in the struct. + */ +#define BLANK(x) memset(x, ' ',sizeof(x)) + BLANK(ret->ident); + BLANK(ret->cmnt); + BLANK(ret->wpt_ident); + BLANK(ret->lnk_ident); + BLANK(ret->subclass); + BLANK(ret->name); + BLANK(ret->facility); + BLANK(ret->addr); + BLANK(ret->cross_road); + BLANK(ret->city); + BLANK(ret->rte_cmnt); + BLANK(ret->rte_ident); + BLANK(ret->rte_link_subclass); + BLANK(ret->rte_link_ident); + BLANK(ret->state); + BLANK(ret->cc); + + ret->facility[0] = 0; + ret->addr[0] = 0; + ret->wpt_ident[0] = 0; +#endif + + ret->lat = ret->lon = GPS_FLTMAX; + ret->dst = 0; + ret->smbl = ret->dspl = ret->colour = ret->alt = ret->prot = INT_MAX; + + if(gps_waypt_type==pD108) + { + ret->dst = 0; + ret->attr = 0x60; + for(i=0;i<7;++i) ret->subclass[i] = 0; + for(i=6;i<18;++i) ret->subclass[i] = 0xff; + } + + return ret; +} + + + +/* @func GPS_Way_Del *********************************************** +** +** Waypoint destructor +** +** @param [w] thys [GPS_Pway *] waypoint to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Way_Del(GPS_PWay *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Gsv_New *********************************************** +** +** Satellites in view constructor +** +** @return [GPS_PGsv] virgin siv +**********************************************************************/ + +GPS_PGsv GPS_Gsv_New(void) +{ + GPS_PGsv ret; + + if(!(ret=(GPS_PGsv)malloc(sizeof(GPS_OGsv)))) + return NULL; + + ret->valid = ret->inview = 0; + *ret->elevation = *ret->azimuth = *ret->strength = '\0'; + + return ret; +} + + + +/* @func GPS_Gsv_Del *********************************************** +** +** Satellites in view destructor +** +** @param [w] thys [GPS_PGsv *] siv to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Gsv_Del(GPS_PGsv *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Rme_New *********************************************** +** +** Position error constructor +** +** @return [GPS_PRme] virgin rme +**********************************************************************/ + +GPS_PRme GPS_Rme_New(void) +{ + GPS_PRme ret; + + if(!(ret=(GPS_PRme)malloc(sizeof(GPS_ORme)))) + return NULL; + + ret->valid = 0; + ret->hpe = ret->vpe = ret->spe = (double)0.; + + return ret; +} + + + +/* @func GPS_Rme_Del *********************************************** +** +** Position error destructor +** +** @param [w] thys [GPS_PRme *] posn error to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Rme_Del(GPS_PRme *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Wpl_New *********************************************** +** +** Waypoint constructor +** +** @return [GPS_PWpl] virgin rme +**********************************************************************/ + +GPS_PWpl GPS_Wpl_New(void) +{ + GPS_PWpl ret; + + if(!(ret=(GPS_PWpl)malloc(sizeof(GPS_OWpl)))) + return NULL; + + ret->valid = 0; + *ret->wpt = '\0'; + ret->lat = ret->lon = (double)0.; + + return ret; +} + + + +/* @func GPS_Wpl_Del *********************************************** +** +** Waypoint destructor +** +** @param [w] thys [GPS_PWpl *] waypoint to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Wpl_Del(GPS_PWpl *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Gll_New *********************************************** +** +** Position (geographic lat/lon) constructor +** +** @return [GPS_PGll] virgin gll +**********************************************************************/ + +GPS_PGll GPS_Gll_New(void) +{ + GPS_PGll ret; + + if(!(ret=(GPS_PGll)malloc(sizeof(GPS_OGll)))) + return NULL; + + ret->valid = 0; + ret->time = (time_t)0; + ret->lat = ret->lon = (double)0.; + ret->dv='\0'; + + return ret; +} + + + +/* @func GPS_Gll_Del *********************************************** +** +** Position destructor +** +** @param [w] thys [GPS_PGll *] posn to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Gll_Del(GPS_PGll *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Rmz_New *********************************************** +** +** Altitude constructor +** +** @return [GPS_PRmz] virgin altitude +**********************************************************************/ + +GPS_PRmz GPS_Rmz_New(void) +{ + GPS_PRmz ret; + + if(!(ret=(GPS_PRmz)malloc(sizeof(GPS_ORmz)))) + return NULL; + + ret->valid = ret->dim = ret->height = 0; + + return ret; +} + + + +/* @func GPS_Rmz_Del *********************************************** +** +** Altitude destructor +** +** @param [w] thys [GPS_PRmz *] altitude to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Rmz_Del(GPS_PRmz *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Rmm_New *********************************************** +** +** Datum constructor +** +** @return [GPS_PRmm] virgin datum +**********************************************************************/ + +GPS_PRmm GPS_Rmm_New(void) +{ + GPS_PRmm ret; + + if(!(ret=(GPS_PRmm)malloc(sizeof(GPS_ORmm)))) + return NULL; + + ret->valid = 0; + *ret->datum = '\0'; + + return ret; +} + + + +/* @func GPS_Rmm_Del *********************************************** +** +** Datum destructor +** +** @param [w] thys [GPS_PRmm *] datum to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Rmm_Del(GPS_PRmm *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Bod_New *********************************************** +** +** Bearing constructor +** +** @return [GPS_PBod] virgin bearing +**********************************************************************/ + +GPS_PBod GPS_Bod_New(void) +{ + GPS_PBod ret; + + if(!(ret=(GPS_PBod)malloc(sizeof(GPS_OBod)))) + return NULL; + + ret->valid = 0; + *ret->dest = *ret->start = '\0'; + ret->True = ret->mag = (double)0.; + + return ret; +} + + + +/* @func GPS_Bod_Del *********************************************** +** +** Bearing destructor +** +** @param [w] thys [GPS_PBod *] bearing to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Bod_Del(GPS_PBod *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Rte_New *********************************************** +** +** Route (NMEA) constructor +** +** @return [GPS_PRte] virgin bearing +**********************************************************************/ + +GPS_PRte GPS_Rte_New(void) +{ + GPS_PRte ret; + + if(!(ret=(GPS_PRte)malloc(sizeof(GPS_ORte)))) + return NULL; + + ret->valid = ret->rte = 0; + ret->type = '\0'; + ret->wpts = NULL; + + return ret; +} + + + +/* @func GPS_Rte_Del *********************************************** +** +** Route (NMEA) destructor +** +** @param [w] thys [GPS_PRte *] route to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Rte_Del(GPS_PRte *thys) +{ + if((*thys)->wpts) + free((void *)(*thys)->wpts); + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Rmc_New *********************************************** +** +** Minimum recommended specific constructor +** +** @return [GPS_PRmc] virgin minimum +**********************************************************************/ + +GPS_PRmc GPS_Rmc_New(void) +{ + GPS_PRmc ret; + + if(!(ret=(GPS_PRmc)malloc(sizeof(GPS_ORmc)))) + return NULL; + + ret->valid = 0; + ret->time = (time_t)0; + *ret->date = ret->warn = '\0'; + ret->lat = ret->lon = ret->speed = ret->cmg = ret->magvar = + (double)0.; + + return ret; +} + + + +/* @func GPS_Rmc_Del *********************************************** +** +** Minimum recommended specific destructor +** +** @param [w] thys [GPS_PRmc *] rec min to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Rmc_Del(GPS_PRmc *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Rmb_New *********************************************** +** +** Minimum recommended nav constructor +** +** @return [GPS_PRmb] virgin minimum nav +**********************************************************************/ + +GPS_PRmb GPS_Rmb_New(void) +{ + GPS_PRmb ret; + + if(!(ret=(GPS_PRmb)malloc(sizeof(GPS_ORmb)))) + return NULL; + + ret->valid = 0; + *ret->owpt = *ret->dwpt = ret->warn = ret->correct = ret->alarm = '\0'; + ret->cross = ret->lat = ret->lon = ret->range = ret->True = ret->velocity = + (double)0.; + + return ret; +} + + + +/* @func GPS_Rmb_Del *********************************************** +** +** Minimum recommended nav destructor +** +** @param [w] thys [GPS_PRmb *] rec min nav to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Rmb_Del(GPS_PRmb *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Gga_New *********************************************** +** +** Fix constructor +** +** @return [GPS_PGga] virgin fix +**********************************************************************/ + +GPS_PGga GPS_Gga_New(void) +{ + GPS_PGga ret; + + if(!(ret=(GPS_PGga)malloc(sizeof(GPS_OGga)))) + return NULL; + + ret->time = (time_t)0.; + ret->valid = ret->qual = ret->nsat = ret->last = ret->dgpsid = 0; + ret->hdil = ret->lat = ret->lon = ret->alt = ret->galt = (double)0.; + + return ret; +} + + + +/* @func GPS_Gga_Del *********************************************** +** +** Fix destructor +** +** @param [w] thys [GPS_PGga *] fix to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Gga_Del(GPS_PGga *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Gsa_New *********************************************** +** +** DOP constructor +** +** @return [GPS_PGsa] virgin DOP +**********************************************************************/ + +GPS_PGsa GPS_Gsa_New(void) +{ + GPS_PGsa ret; + + if(!(ret=(GPS_PGsa)malloc(sizeof(GPS_OGsa)))) + return NULL; + + ret->type = '\0'; + ret->valid = ret->nsat = ret->fix = 0; + ret->pdop = ret->hdop = ret->vdop = (double)0.; + + return ret; +} + + + +/* @func GPS_Gsa_Del *********************************************** +** +** DOP destructor +** +** @param [w] thys [GPS_PGsa *] DOP to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Gsa_Del(GPS_PGsa *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Apb_New *********************************************** +** +** Autopilot B constructor +** +** @return [GPS_PApb] virgin autopilot +**********************************************************************/ + +GPS_PApb GPS_Apb_New(void) +{ + GPS_PApb ret; + + if(!(ret=(GPS_PApb)malloc(sizeof(GPS_OApb)))) + return NULL; + + ret->blink = ret->warn = ret->steer = ret->unit = ret->alarmc = + ret->alarmp = *ret->wpt = '\0'; + ret->valid = 0; + ret->edist = ret->od = ret->pd = ret->hdg = (double)0.; + + return ret; +} + + + +/* @func GPS_Apb_Del *********************************************** +** +** Autopilot destructor +** +** @param [w] thys [GPS_PApb *] autopilot to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Apb_Del(GPS_PApb *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Bwc_New *********************************************** +** +** Waypoint bng constructor +** +** @return [GPS_PBwc] virgin waypoint bng +**********************************************************************/ + +GPS_PBwc GPS_Bwc_New(void) +{ + GPS_PBwc ret; + + if(!(ret=(GPS_PBwc)malloc(sizeof(GPS_OBwc)))) + return NULL; + + *ret->wpt = '\0'; + ret->time = (time_t)0; + ret->valid = 0; + ret->lat = ret->lon = ret->True = ret->mag = ret->dist = (double)0.; + + return ret; +} + + + +/* @func GPS_Bwc_Del *********************************************** +** +** Waypoint bearing destructor +** +** @param [w] thys [GPS_PBwc *] waypoint bearing to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Bwc_Del(GPS_PBwc *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Bwr_New *********************************************** +** +** Waypoint bng rhumb constructor +** +** @return [GPS_PBwr] virgin waypoint bng +**********************************************************************/ + +GPS_PBwr GPS_Bwr_New(void) +{ + GPS_PBwr ret; + + if(!(ret=(GPS_PBwr)malloc(sizeof(GPS_OBwr)))) + return NULL; + + *ret->wpt = '\0'; + ret->time = (time_t)0; + ret->valid = 0; + ret->lat = ret->lon = ret->True = ret->mag = ret->dist = (double)0.; + + return ret; +} + + + +/* @func GPS_Bwr_Del *********************************************** +** +** Waypoint bearing rhumb destructor +** +** @param [w] thys [GPS_PBwr *] waypoint bearing rhumb to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Bwr_Del(GPS_PBwr *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Dbt_New *********************************************** +** +** Depth constructor +** +** @return [GPS_PDbt] virgin depth +**********************************************************************/ + +GPS_PDbt GPS_Dbt_New(void) +{ + GPS_PDbt ret; + + if(!(ret=(GPS_PDbt)malloc(sizeof(GPS_ODbt)))) + return NULL; + + ret->valid = 0; + ret->f = ret->m = (double)0.; + + return ret; +} + + + +/* @func GPS_Dbt_Del *********************************************** +** +** Depth destructor +** +** @param [w] thys [GPS_PDbt *] depth to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Dbt_Del(GPS_PDbt *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Hdm_New *********************************************** +** +** Magnetic heading constructor +** +** @return [GPS_PHdm] virgin hdg +**********************************************************************/ + +GPS_PHdm GPS_Hdm_New(void) +{ + GPS_PHdm ret; + + if(!(ret=(GPS_PHdm)malloc(sizeof(GPS_OHdm)))) + return NULL; + + ret->valid = 0; + ret->hdg = (double)0.; + + return ret; +} + + + +/* @func GPS_Hdm_Del *********************************************** +** +** Magnetic heading destructor +** +** @param [w] thys [GPS_PHdm *] mag hdg to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Hdm_Del(GPS_PHdm *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Hsc_New *********************************************** +** +** Heading to steer constructor +** +** @return [GPS_PHsc] virgin hdg +**********************************************************************/ + +GPS_PHsc GPS_Hsc_New(void) +{ + GPS_PHsc ret; + + if(!(ret=(GPS_PHsc)malloc(sizeof(GPS_OHsc)))) + return NULL; + + ret->valid = 0; + ret->True = ret->mag = (double)0.; + + return ret; +} + + + +/* @func GPS_Hsc_Del *********************************************** +** +** Heading to steer destructor +** +** @param [w] thys [GPS_PHsc *] hdg to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Hsc_Del(GPS_PHsc *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Mtw_New *********************************************** +** +** Water temp constructor +** +** @return [GPS_PMtw] virgin temp +**********************************************************************/ + +GPS_PMtw GPS_Mtw_New(void) +{ + GPS_PMtw ret; + + if(!(ret=(GPS_PMtw)malloc(sizeof(GPS_OMtw)))) + return NULL; + + ret->valid = 0; + ret->T = (double)0.; + + return ret; +} + + + +/* @func GPS_Mtw_Del *********************************************** +** +** Water temperature destructor +** +** @param [w] thys [GPS_PMtw *] water temp to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Mtw_Del(GPS_PMtw *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_R00_New *********************************************** +** +** Waypoint list constructor +** +** @return [GPS_PR00] virgin wpt list +**********************************************************************/ + +GPS_PR00 GPS_R00_New(void) +{ + GPS_PR00 ret; + + if(!(ret=(GPS_PR00)malloc(sizeof(GPS_OR00)))) + return NULL; + + ret->valid = 0; + *ret->wpts='\0'; + + return ret; +} + + + +/* @func GPS_R00_Del *********************************************** +** +** Waypoint list destructor +** +** @param [w] thys [GPS_PR00 *] waypoint list to delete +** +** @return [void] +**********************************************************************/ + +void GPS_R00_Del(GPS_PR00 *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Vhw_New *********************************************** +** +** Water speed constructor +** +** @return [GPS_PVhw] virgin water speed +**********************************************************************/ + +GPS_PVhw GPS_Vhw_New(void) +{ + GPS_PVhw ret; + + if(!(ret=(GPS_PVhw)malloc(sizeof(GPS_OVhw)))) + return NULL; + + ret->valid = 0; + ret->True = ret->mag = ret->wspeed = ret->speed = (double)0.; + + return ret; +} + + + +/* @func GPS_Vhw_Del *********************************************** +** +** Water speed destructor +** +** @param [w] thys [GPS_PVhw *] waypoint list to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Vhw_Del(GPS_PVhw *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Vwr_New *********************************************** +** +** Wind constructor +** +** @return [GPS_PVwr] virgin wind +**********************************************************************/ + +GPS_PVwr GPS_Vwr_New(void) +{ + GPS_PVwr ret; + + if(!(ret=(GPS_PVwr)malloc(sizeof(GPS_OVwr)))) + return NULL; + + ret->wdir = '\0'; + ret->valid = 0; + ret->wind = ret->knots = ret->ms = ret->khr = (double)0.; + + return ret; +} + + + +/* @func GPS_Vwr_Del *********************************************** +** +** Wind destructor +** +** @param [w] thys [GPS_PVwr *] wind to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Vwr_Del(GPS_PVwr *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Vtg_New *********************************************** +** +** Track made good constructor +** +** @return [GPS_PVtg] virgin tmg +**********************************************************************/ + +GPS_PVtg GPS_Vtg_New(void) +{ + GPS_PVtg ret; + + if(!(ret=(GPS_PVtg)malloc(sizeof(GPS_OVtg)))) + return NULL; + + ret->valid = 0; + ret->True = ret->mag = ret->knots = ret->khr = (double)0.; + + return ret; +} + + + +/* @func GPS_Vtg_Del *********************************************** +** +** Track made good destructor +** +** @param [w] thys [GPS_PVtg *] tmg to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Vtg_Del(GPS_PVtg *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Xte_New *********************************************** +** +** Cross track error constructor +** +** @return [GPS_Xte] virgin xte +**********************************************************************/ + +GPS_PXte GPS_Xte_New(void) +{ + GPS_PXte ret; + + if(!(ret=(GPS_PXte)malloc(sizeof(GPS_OXte)))) + return NULL; + + ret->valid = 0; + ret->warn = ret->cycle = ret->steer = ret->unit = '\0'; + ret->dist = (double)0.; + + return ret; +} + + + +/* @func GPS_Xte_Del *********************************************** +** +** Cross track error destructor +** +** @param [w] thys [GPS_PXte *] xte to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Xte_Del(GPS_PXte *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Xtr_New *********************************************** +** +** Cross track error dead constructor +** +** @return [GPS_Xtr] virgin xtr +**********************************************************************/ + +GPS_PXtr GPS_Xtr_New(void) +{ + GPS_PXtr ret; + + if(!(ret=(GPS_PXtr)malloc(sizeof(GPS_OXtr)))) + return NULL; + + ret->valid = 0; + ret->steer = ret->unit = '\0'; + ret->dist = (double)0.; + + return ret; +} + + + +/* @func GPS_Xtr_Del *********************************************** +** +** Cross track error dead destructor +** +** @param [w] thys [GPS_PXtr *] xtr to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Xtr_Del(GPS_PXtr *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Lib_New *********************************************** +** +** Link constructor +** +** @return [GPS_Lib] virgin link +**********************************************************************/ + +GPS_PLib GPS_Lib_New(void) +{ + GPS_PLib ret; + + if(!(ret=(GPS_PLib)malloc(sizeof(GPS_OLib)))) + return NULL; + + ret->valid = 0; + ret->rqst = '\0'; + ret->freq = ret->baud = (double)0.; + + return ret; +} + + + +/* @func GPS_Lib_Del *********************************************** +** +** Link destructor +** +** @param [w] thys [GPS_PLib *] link to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Lib_Del(GPS_PLib *thys) +{ + free((void *)*thys); + + return; +} + + + + +/* @func GPS_Nmea_New *********************************************** +** +** Nmea data constructor +** +** @return [GPS_PNmea] virgin nmea data +**********************************************************************/ + +GPS_PNmea GPS_Nmea_New(void) +{ + GPS_PNmea ret; + + if(!(ret=(GPS_PNmea)malloc(sizeof(GPS_ONmea)))) + return NULL; + + ret->gsv = GPS_Gsv_New(); + ret->rme = GPS_Rme_New(); + ret->gll = GPS_Gll_New(); + ret->rmz = GPS_Rmz_New(); + ret->rmm = GPS_Rmm_New(); + ret->bod = GPS_Bod_New(); + ret->rte = GPS_Rte_New(); + ret->wpl = GPS_Wpl_New(); + ret->rmc = GPS_Rmc_New(); + ret->rmb = GPS_Rmb_New(); + ret->gga = GPS_Gga_New(); + ret->gsa = GPS_Gsa_New(); + ret->apb = GPS_Apb_New(); + ret->bwc = GPS_Bwc_New(); + ret->bwr = GPS_Bwr_New(); + ret->dbt = GPS_Dbt_New(); + ret->hdm = GPS_Hdm_New(); + ret->hsc = GPS_Hsc_New(); + ret->mtw = GPS_Mtw_New(); + ret->r00 = GPS_R00_New(); + ret->vhw = GPS_Vhw_New(); + ret->vwr = GPS_Vwr_New(); + ret->vtg = GPS_Vtg_New(); + ret->xte = GPS_Xte_New(); + ret->xtr = GPS_Xtr_New(); + ret->lib = GPS_Lib_New(); + + return ret; +} + + + +/* @func GPS_Nmea_Del *********************************************** +** +** NMEA data destructor +** +** @param [w] thys [GPS_PNmea *] nmea data to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Nmea_Del(GPS_PNmea *thys) +{ + + GPS_Gsv_Del(&(*thys)->gsv); + GPS_Rme_Del(&(*thys)->rme); + GPS_Gll_Del(&(*thys)->gll); + GPS_Rmz_Del(&(*thys)->rmz); + GPS_Rmm_Del(&(*thys)->rmm); + GPS_Bod_Del(&(*thys)->bod); + GPS_Rte_Del(&(*thys)->rte); + GPS_Wpl_Del(&(*thys)->wpl); + GPS_Rmc_Del(&(*thys)->rmc); + GPS_Rmb_Del(&(*thys)->rmb); + GPS_Gga_Del(&(*thys)->gga); + GPS_Gsa_Del(&(*thys)->gsa); + GPS_Apb_Del(&(*thys)->apb); + GPS_Bwc_Del(&(*thys)->bwc); + GPS_Bwr_Del(&(*thys)->bwr); + GPS_Dbt_Del(&(*thys)->dbt); + GPS_Hdm_Del(&(*thys)->hdm); + GPS_Hsc_Del(&(*thys)->hsc); + GPS_Mtw_Del(&(*thys)->mtw); + GPS_R00_Del(&(*thys)->r00); + GPS_Vhw_Del(&(*thys)->vhw); + GPS_Vwr_Del(&(*thys)->vwr); + GPS_Vtg_Del(&(*thys)->vtg); + GPS_Xte_Del(&(*thys)->xte); + GPS_Xtr_Del(&(*thys)->xtr); + GPS_Lib_Del(&(*thys)->lib); + + free((void *)*thys); + + return; +} diff --git a/jeeps/gpsmem.h b/jeeps/gpsmem.h new file mode 100644 index 000000000..8a52fad2e --- /dev/null +++ b/jeeps/gpsmem.h @@ -0,0 +1,88 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsmem_h +#define gpsmem_h + + +#include "gps.h" + +GPS_PPacket GPS_Packet_New(void); +void GPS_Packet_Del(GPS_PPacket *thys); +GPS_PPvt_Data GPS_Pvt_New(void); +void GPS_Pvt_Del(GPS_PPvt_Data *thys); +GPS_PAlmanac GPS_Almanac_New(void); +void GPS_Almanac_Del(GPS_PAlmanac *thys); +GPS_PTrack GPS_Track_New(void); +void GPS_Track_Del(GPS_PTrack *thys); +GPS_PWay GPS_Way_New(void); +void GPS_Way_Del(GPS_PWay *thys); + + +/* + * NMEA Section + */ +GPS_PGsv GPS_Gsv_New(void); +void GPS_Gsv_Del(GPS_PGsv *thys); +GPS_PRme GPS_Rme_New(void); +void GPS_Rme_Del(GPS_PRme *thys); +GPS_PGll GPS_Gll_New(void); +void GPS_Gll_Del(GPS_PGll *thys); +GPS_PRmz GPS_Rmz_New(void); +void GPS_Rmz_Del(GPS_PRmz *thys); +GPS_PRmm GPS_Rmm_New(void); +void GPS_Rmm_Del(GPS_PRmm *thys); +GPS_PBod GPS_Bod_New(void); +void GPS_Bod_Del(GPS_PBod *thys); +GPS_PRte GPS_Rte_New(void); +void GPS_Rte_Del(GPS_PRte *thys); +GPS_PRmc GPS_Rmc_New(void); +void GPS_Rmc_Del(GPS_PRmc *thys); +GPS_PRmb GPS_Rmb_New(void); +void GPS_Rmb_Del(GPS_PRmb *thys); +GPS_PGga GPS_Gga_New(void); +void GPS_Gga_Del(GPS_PGga *thys); +GPS_PGsa GPS_Gsa_New(void); +void GPS_Gsa_Del(GPS_PGsa *thys); +GPS_PApb GPS_Apb_New(void); +void GPS_Apb_Del(GPS_PApb *thys); +GPS_PBwc GPS_Bwc_New(void); +void GPS_Bwc_Del(GPS_PBwc *thys); +GPS_PBwr GPS_Bwr_New(void); +void GPS_Bwr_Del(GPS_PBwr *thys); +GPS_PDbt GPS_Dbt_New(void); +void GPS_Dbt_Del(GPS_PDbt *thys); +GPS_PHdm GPS_Hdm_New(void); +void GPS_Hdm_Del(GPS_PHdm *thys); +GPS_PHsc GPS_Hsc_New(void); +void GPS_Hsc_Del(GPS_PHsc *thys); +GPS_PMtw GPS_Mtw_New(void); +void GPS_Mtw_Del(GPS_PMtw *thys); +GPS_PR00 GPS_R00_New(void); +void GPS_R00_Del(GPS_PR00 *thys); +GPS_PVhw GPS_Vhw_New(void); +void GPS_Vhw_Del(GPS_PVhw *thys); +GPS_PVwr GPS_Vwr_New(void); +void GPS_Vwr_Del(GPS_PVwr *thys); +GPS_PVtg GPS_Vtg_New(void); +void GPS_Vtg_Del(GPS_PVtg *thys); +GPS_PXte GPS_Xte_New(void); +void GPS_Xte_Del(GPS_PXte *thys); +GPS_PXtr GPS_Xtr_New(void); +void GPS_Xtr_Del(GPS_PXtr *thys); +GPS_PLib GPS_Lib_New(void); +void GPS_Lib_Del(GPS_PLib *thys); +GPS_PWpl GPS_Wpl_New(void); +void GPS_Wpl_Del(GPS_PWpl *thys); +GPS_PNmea GPS_Nmea_New(void); +void GPS_Nmea_Del(GPS_PNmea *thys); + + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsnmea.h b/jeeps/gpsnmea.h new file mode 100644 index 000000000..53255c65a --- /dev/null +++ b/jeeps/gpsnmea.h @@ -0,0 +1,312 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsnmea_h +#define gpsnmea_h + + +#include "gps.h" + + +typedef struct GPS_SGsv +{ + int32 inview; + int32 prn[32]; + int32 elevation[32]; + int32 azimuth[32]; + int32 strength[32]; + int32 valid; +} GPS_OGsv,*GPS_PGsv; + +typedef struct GPS_SRme +{ + double hpe; + double vpe; + double spe; + int32 valid; +} GPS_ORme,*GPS_PRme; + +typedef struct GPS_SGll +{ + double lat; + double lon; + time_t time; + char dv; + int32 valid; +} GPS_OGll,*GPS_PGll; + +typedef struct GPS_SRmz +{ + int32 height; + int32 dim; + int32 valid; +} GPS_ORmz,*GPS_PRmz; + +typedef struct GPS_SRmm +{ + char datum[83]; + int32 valid; +} GPS_ORmm,*GPS_PRmm; + +typedef struct GPS_SBod +{ + double True; + double mag; + char dest[83]; + char start[83]; + int32 valid; +} GPS_OBod,*GPS_PBod; + +typedef struct GPS_SRte +{ + char type; + int32 rte; + char *wpts; + int32 valid; +} GPS_ORte,*GPS_PRte; + +typedef struct GPS_SWpl +{ + double lat; + double lon; + char wpt[83]; + int32 valid; +} GPS_OWpl,*GPS_PWpl; + +typedef struct GPS_SRmc +{ + time_t time; + char warn; + double lat; + double lon; + double speed; + double cmg; + char date[83]; + double magvar; + int32 valid; +} GPS_ORmc,*GPS_PRmc; + +typedef struct GPS_SRmb +{ + char warn; + double cross; + char correct; + char owpt[83]; + char dwpt[83]; + double lat; + double lon; + double range; + double True; + double velocity; + char alarm; + int32 valid; +} GPS_ORmb,*GPS_PRmb; + +typedef struct GPS_SGga +{ + time_t time; + double lat; + double lon; + int32 qual; + int32 nsat; + double hdil; + double alt; + double galt; + int32 last; + int32 dgpsid; + int32 valid; +} GPS_OGga,*GPS_PGga; + +typedef struct GPS_SGsa +{ + char type; + int32 fix; + int32 nsat; + int32 prn[12]; + double pdop; + double hdop; + double vdop; + int32 valid; +} GPS_OGsa,*GPS_PGsa; + +typedef struct GPS_SApb +{ + char blink; + char warn; + double edist; + char steer; + char unit; + char alarmc; + char alarmp; + double od; + char wpt[83]; + double pd; + double hdg; + int32 valid; +} GPS_OApb,*GPS_PApb; + +typedef struct GPS_SBwc +{ + time_t time; + double lat; + double lon; + double True; + double mag; + double dist; + char wpt[83]; + int32 valid; +} GPS_OBwc,*GPS_PBwc; + +typedef struct GPS_SBwr +{ + time_t time; + double lat; + double lon; + double True; + double mag; + double dist; + char wpt[83]; + int32 valid; +} GPS_OBwr,*GPS_PBwr; + +typedef struct GPS_SDbt +{ + double f; + double m; + int32 valid; +} GPS_ODbt,*GPS_PDbt; + +typedef struct GPS_SHdm +{ + double hdg; + int32 valid; +} GPS_OHdm,*GPS_PHdm; + +typedef struct GPS_SHsc +{ + double True; + double mag; + int32 valid; +} GPS_OHsc,*GPS_PHsc; + +typedef struct GPS_SMtw +{ + double T; + int32 valid; +} GPS_OMtw,*GPS_PMtw; + +typedef struct GPS_SR00 +{ + char wpts[83]; + int32 valid; +} GPS_OR00,*GPS_PR00; + +typedef struct GPS_SVhw +{ + double True; + double mag; + double wspeed; + double speed; + int32 valid; +} GPS_OVhw,*GPS_PVhw; + +typedef struct GPS_SVwr +{ + double wind; + char wdir; + double knots; + double ms; + double khr; + int32 valid; +} GPS_OVwr,*GPS_PVwr; + +typedef struct GPS_SVtg +{ + double True; + double mag; + double knots; + double khr; + int32 valid; +} GPS_OVtg,*GPS_PVtg; + +typedef struct GPS_SXte +{ + char warn; + char cycle; + double dist; + char steer; + char unit; + int32 valid; +} GPS_OXte,*GPS_PXte; + +typedef struct GPS_SXtr +{ + double dist; + char steer; + char unit; + int32 valid; +} GPS_OXtr,*GPS_PXtr; + +typedef struct GPS_SLib +{ + double freq; + double baud; + char rqst; + int32 valid; +} GPS_OLib,*GPS_PLib; + + +typedef struct GPS_SNmea +{ + GPS_PGsv gsv; + GPS_PRme rme; + GPS_PGll gll; + GPS_PRmz rmz; + GPS_PRmm rmm; + GPS_PBod bod; + GPS_PRte rte; + GPS_PWpl wpl; + GPS_PRmc rmc; + GPS_PRmb rmb; + GPS_PGga gga; + GPS_PGsa gsa; + GPS_PApb apb; + GPS_PBwc bwc; + GPS_PBwr bwr; + GPS_PDbt dbt; + GPS_PHdm hdm; + GPS_PHsc hsc; + GPS_PMtw mtw; + GPS_PR00 r00; + GPS_PVhw vhw; + GPS_PVwr vwr; + GPS_PVtg vtg; + GPS_PXte xte; + GPS_PXtr xtr; + GPS_PLib lib; +} GPS_ONmea,*GPS_PNmea; + + + + + + +extern int32 gps_fd; /* FD for serial port access [NMEA] */ +extern GPS_PNmea gps_nmea; /* Internal nmea data repository */ + + + +void GPS_NMEA_Add_Checksum(char *s); +int32 GPS_NMEA_Line_Check(const char *s); +int32 GPS_NMEA_Load(int32 fd); +int32 GPS_NMEA_Init(const char *s); +void GPS_NMEA_Exit(void); +int32 GPS_NMEA_Send(const char *s, int32 flag); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsnmeafmt.h b/jeeps/gpsnmeafmt.h new file mode 100644 index 000000000..91d38041c --- /dev/null +++ b/jeeps/gpsnmeafmt.h @@ -0,0 +1,44 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsnmeafmt_h +#define gpsnmeafmt_h + + +#include "gps.h" + +int32 GPS_NMEA_Apb_Scan(const char *s, GPS_PApb *thys); +int32 GPS_NMEA_Bod_Scan(const char *s, GPS_PBod *thys); +int32 GPS_NMEA_Bwc_Scan(const char *s, GPS_PBwc *thys); +int32 GPS_NMEA_Bwr_Scan(const char *s, GPS_PBwr *thys); +int32 GPS_NMEA_Dbt_Scan(const char *s, GPS_PDbt *thys); +int32 GPS_NMEA_Gga_Scan(const char *s, GPS_PGga *thys); +int32 GPS_NMEA_Gll_Scan(const char *s, GPS_PGll *thys); +int32 GPS_NMEA_Gsa_Scan(const char *s, GPS_PGsa *thys); +int32 GPS_NMEA_Gsv_Scan(const char *s, GPS_PGsv *thys); +int32 GPS_NMEA_Hdm_Scan(const char *s, GPS_PHdm *thys); +int32 GPS_NMEA_Hsc_Scan(const char *s, GPS_PHsc *thys); +int32 GPS_NMEA_Mtw_Scan(const char *s, GPS_PMtw *thys); +int32 GPS_NMEA_R00_Scan(const char *s, GPS_PR00 *thys); +int32 GPS_NMEA_Rmb_Scan(const char *s, GPS_PRmb *thys); +int32 GPS_NMEA_Rmc_Scan(const char *s, GPS_PRmc *thys); +int32 GPS_NMEA_Rte_Scan(const char *s, GPS_PRte *thys); +int32 GPS_NMEA_Vhw_Scan(const char *s, GPS_PVhw *thys); +int32 GPS_NMEA_Vwr_Scan(const char *s, GPS_PVwr *thys); +int32 GPS_NMEA_Vtg_Scan(const char *s, GPS_PVtg *thys); +int32 GPS_NMEA_Wpl_Scan(const char *s, GPS_PWpl *thys); +int32 GPS_NMEA_Xte_Scan(const char *s, GPS_PXte *thys); +int32 GPS_NMEA_Xtr_Scan(const char *s, GPS_PXtr *thys); +int32 GPS_NMEA_Rme_Scan(const char *s, GPS_PRme *thys); +int32 GPS_NMEA_Rmz_Scan(const char *s, GPS_PRmz *thys); +int32 GPS_NMEA_Rmm_Scan(const char *s, GPS_PRmm *thys); +int32 GPS_NMEA_Lib_Scan(const char *s, GPS_PLib *thys); + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsnmeaget.h b/jeeps/gpsnmeaget.h new file mode 100644 index 000000000..17cba4801 --- /dev/null +++ b/jeeps/gpsnmeaget.h @@ -0,0 +1,43 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsnmearead_h +#define gpsnmearead_h + + +#include "gps.h" + +int32 GPS_NMEA_Get_Apb(GPS_PApb *thys); +int32 GPS_NMEA_Get_Bod(GPS_PBod *thys); +int32 GPS_NMEA_Get_Bwc(GPS_PBwc *thys); +int32 GPS_NMEA_Get_Bwr(GPS_PBwr *thys); +int32 GPS_NMEA_Get_Dbt(GPS_PDbt *thys); +int32 GPS_NMEA_Get_Gga(GPS_PGga *thys); +int32 GPS_NMEA_Get_Gll(GPS_PGll *thys); +int32 GPS_NMEA_Get_Gsa(GPS_PGsa *thys); +int32 GPS_NMEA_Get_Gsv(GPS_PGsv *thys); +int32 GPS_NMEA_Get_Hdm(GPS_PHdm *thys); +int32 GPS_NMEA_Get_Hsc(GPS_PHsc *thys); +int32 GPS_NMEA_Get_Mtw(GPS_PMtw *thys); +int32 GPS_NMEA_Get_R00(GPS_PR00 *thys); +int32 GPS_NMEA_Get_Rmb(GPS_PRmb *thys); +int32 GPS_NMEA_Get_Rmc(GPS_PRmc *thys); +int32 GPS_NMEA_Get_Rte(GPS_PRte *thys); +int32 GPS_NMEA_Get_Vhw(GPS_PVhw *thys); +int32 GPS_NMEA_Get_Vwr(GPS_PVwr *thys); +int32 GPS_NMEA_Get_Vtg(GPS_PVtg *thys); +int32 GPS_NMEA_Get_Wpl(GPS_PWpl *thys); +int32 GPS_NMEA_Get_Xte(GPS_PXte *thys); +int32 GPS_NMEA_Get_Xtr(GPS_PXtr *thys); +int32 GPS_NMEA_Get_Rme(GPS_PRme *thys); +int32 GPS_NMEA_Get_Rmz(GPS_PRmz *thys); +int32 GPS_NMEA_Get_Rmm(GPS_PRmm *thys); +int32 GPS_NMEA_Get_Lib(GPS_PLib *thys); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsport.h b/jeeps/gpsport.h new file mode 100644 index 000000000..040efd2e7 --- /dev/null +++ b/jeeps/gpsport.h @@ -0,0 +1,16 @@ +/* + * For portability any '32' type must be 32 bits + * and '16' type must be 16 bits + */ +typedef unsigned char UC; +typedef short int16; +typedef unsigned short uint16; +typedef uint16 US; + +#if defined(__alpha) +typedef int int32; +typedef unsigned int uint32; +#else +typedef long int32; +typedef unsigned long uint32; +#endif diff --git a/jeeps/gpsproj.c b/jeeps/gpsproj.c new file mode 100644 index 000000000..c2634b370 --- /dev/null +++ b/jeeps/gpsproj.c @@ -0,0 +1,4485 @@ +/******************************************************************** +** @source JEEPS projection functions +** +** @author Copyright (C) 1999 Alan Bleasby +** @version 1.0 +** @modified Feb 04 2000 Alan Bleasby. First version +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include +#include + + +/* @func GPS_Math_Albers_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Albers projection easting and +** northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi1 [double] standard latitude (parallel) 1 (deg) +** @param [r] phi2 [double] standard latitude (parallel) 2 (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Albers_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi1, double phi2, + double phi0, double M0, double E0, + double N0, double a, double b) + +{ + double dlambda; + double phis; + double phic; + double e; + double esq; + double esqs; + double omesqs2; + + double a2; + double b2; + double q; + double q0; + double q1; + double q2; + double m1; + double m2; + double n; + double phi0s; + double phi1s; + double phi1c; + double phi2s; + double phi2c; + double ess; + double om0; + double m1sq; + double C; + double nq; + double nq0; + double rho; + double rho0; + double theta; + + phi = GPS_Math_Deg_To_Rad(phi); + phi0 = GPS_Math_Deg_To_Rad(phi0); + phi1 = GPS_Math_Deg_To_Rad(phi1); + phi2 = GPS_Math_Deg_To_Rad(phi2); + lambda = GPS_Math_Deg_To_Rad(lambda); + M0 = GPS_Math_Deg_To_Rad(M0); + + dlambda = lambda - M0; + if(dlambda > GPS_PI) + dlambda -= ((double)2.0 * GPS_PI); + if(dlambda < -GPS_PI) + dlambda += ((double)2.0 * GPS_PI); + + phis = sin(phi); + phic = cos(phi); + + a2 = a*a; + b2 = b*b; + esq = (a2-b2)/a2; + e = pow(esq,(double)0.5); + + + phi0s = sin(phi0); + ess = e * phi0s; + om0 = ((double)1.0 - ess*ess); + q0 = ((double)1.0 - esq) * (phi0s / om0-((double)1.0/(e+e)) * + log(((double)1.0-ess)/((double)1.0+ess))); + phi1s = sin(phi1); + phi1c = cos(phi1); + ess = e * phi1s; + om0 = ((double)1.0 - ess*ess); + m1 = phi1c/pow(om0,(double)0.5); + q1 = ((double)1.0 - esq) * (phi1s / om0-((double)1.0/(e+e)) * + log(((double)1.0-ess)/((double)1.0+ess))); + + m1sq = m1*m1; + if(fabs(phi1-phi2)>1.0e-10) + { + phi2s = sin(phi2); + phi2c = cos(phi2); + ess = e * phi2s; + om0 = ((double)1.0 - ess*ess); + m2 = phi2c/pow(om0,(double)0.5); + q2 = ((double)1.0 - esq) * (phi2s / om0-((double)1.0/(e+e)) * + log(((double)1.0-ess)/((double)1.0+ess))); + n = (m1sq - m2*m2) / (q2-q1); + } + else + n = phi1s; + + C = m1sq + n*q1; + nq0 = n * q0; + if(C < nq0) + rho0 = (double)0.; + else + rho0 = (a/n) * pow(C-nq0,(double)0.5); + + + esqs = e * phis; + omesqs2 = ((double)1.0 - esqs*esqs); + q = ((double)1.0 - esq) * (phis / omesqs2-((double)1.0/(e+e)) * + log(((double)1.0-esqs)/((double)1.0+esqs))); + nq = n*q; + if(C1.0e-10) + { + phi2s = sin(phi2); + phi2c = cos(phi2); + ess = e * phi2s; + om0 = ((double)1.0 - ess*ess); + m2 = phi2c/pow(om0,(double)0.5); + q2 = ((double)1.0 - esq) * (phi2s / om0-((double)1.0/(e+e)) * + log(((double)1.0-ess)/((double)1.0+ess))); + n = (m1sq - m2*m2) / (q2-q1); + } + else + n = phi1s; + + C = m1sq + n*q1; + nq0 = n * q0; + if(C < nq0) + rho0 = (double)0.; + else + rho0 = (a/n) * pow(C-nq0,(double)0.5); + + + dphi = (double) 1.0; + theta = (double) 0.0; + tol = (double) 4.85e-10; + po2 = (double)GPS_PI / (double)2.0; + + dy = N-N0; + dx = E-E0; + rhom = rho0-dy; + rho = pow(dx*dx+rhom*rhom,(double)0.5); + + if(n<0.0) + { + rho *= (double)-1.0; + dx *= (double)-1.0; + dy *= (double)-1.0; + rhom *= (double)-1.0; + } + + if(rho) + theta = atan2(dx,rhom); + rhon = rho*n; + q = (C - (rhon*rhon) / a2) / n; + qc = (double)1.0 - ((double)1.0 / (e+e)) * + log(((double)1.0-e)/((double)1.0+e)); + if(fabs(fabs(qc)-fabs(q))>1.9e-6) + { + qd2 = q/(double)2.0; + if(qd2>1.0) + *phi = po2; + else if(qd2<-1.0) + *phi = -po2; + else + { + lat = asin(qd2); + if(e<1.0e-10) + *phi = lat; + else + { + while(fabs(dphi)>tol) + { + phis = sin(lat); + ess = e*phis; + om0 = ((double)1.0 - ess*ess); + dphi = (om0*om0) / ((double)2.0*cos(lat))* + (q/((double)1.0-esq) - phis / om0 + + (log(((double)1.0-ess)/((double)1.0+ess)) / + (e+e))); + lat += dphi; + } + *phi = lat; + } + + if(*phi > po2) + *phi = po2; + else if(*phi<-po2) + *phi = -po2; + } + } + else + { + if(q>=0.0) + *phi = po2; + else + *phi = -po2; + } + + *lambda = M0 + theta / n; + if(*lambda > GPS_PI) + *lambda -= GPS_PI * (double)2.0; + if(*lambda < -GPS_PI) + *lambda += GPS_PI * (double)2.0; + if(*lambda>GPS_PI) + *lambda = GPS_PI; + else if(*lambda<-GPS_PI) + *lambda = -GPS_PI; + + *phi = GPS_Math_Rad_To_Deg(*phi); + *lambda = GPS_Math_Rad_To_Deg(*lambda); + + return; +} + + + +/* @func GPS_Math_LambertCC_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Lambert Conformal Conic projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi1 [double] standard latitude (parallel) 1 (deg) +** @param [r] phi2 [double] standard latitude (parallel) 2 (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_LambertCC_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi1, double phi2, + double phi0, double M0, double E0, + double N0, double a, double b) + +{ + double po2; + double po4; + double a2; + double b2; + double phi0s; + double e; + double esq; + double ed2; + double ess; + double t0; + double t1; + double t2; + double m1; + double m2; + double phi1s; + double phi1c; + double phi2s; + double phi2c; + double n; + double F; + double Fa; + double rho; + double rho0; + double phis; + double t; + double theta; + double dphi; + + phi = GPS_Math_Deg_To_Rad(phi); + phi0 = GPS_Math_Deg_To_Rad(phi0); + phi1 = GPS_Math_Deg_To_Rad(phi1); + phi2 = GPS_Math_Deg_To_Rad(phi2); + lambda = GPS_Math_Deg_To_Rad(lambda); + M0 = GPS_Math_Deg_To_Rad(M0); + + + po2 = (double)GPS_PI / (double)2.0; + po4 = (double)GPS_PI / (double)4.0; + a2 = a*a; + b2 = b*b; + esq = (a2-b2)/a2; + e = pow(esq,(double)0.5); + ed2 = e / (double)2.0; + + phi0s = sin(phi0); + ess = e * phi0s; + t0 = tan(po4-phi0/(double)2.0) / pow(((double)1.0-ess) / + ((double)1.0+ess),ed2); + + + phi1s = sin(phi1); + phi1c = cos(phi1); + ess = e * phi1s; + m1 = phi1c / pow(((double)1.0-ess*ess),(double)0.5); + t1 = tan(po4-phi1/(double)2.0) / pow(((double)1.0-ess) / + ((double)1.0+ess),ed2); + + if(fabs(phi1-phi2)>1.0e-10) + { + phi2s = sin(phi2); + phi2c = cos(phi2); + ess = e * phi2s; + m2 = phi2c / pow(((double)1.0-ess*ess),(double)0.5); + t2 = tan(po4-phi2/(double)2.0) / pow(((double)1.0-ess) / + ((double)1.0+ess),ed2); + n = log(m1/m2) / log(t1/t2); + } + else + n = phi1s; + + F = m1 / (n*pow(t1,n)); + Fa = F*a; + + rho0 = pow(t0,n) * Fa; + + if(fabs(fabs(phi)-po2)>1.0e-10) + { + phis = sin(phi); + ess = e * phis; + t = tan(po4-phi/(double)2.0) / pow(((double)1.0-ess) / + ((double)1.0+ess),ed2); + rho = pow(t,n) * Fa; + } + else + { + if((phi*n)<=(double)0.0) + return; + rho = (double)0.0; + } + + dphi = lambda - M0; + if(dphi>GPS_PI) + dphi -= (double)GPS_PI * (double)2.0; + if(dphi<-GPS_PI) + dphi += (double)GPS_PI * (double)2.0; + theta = dphi*n; + + *E = rho * sin(theta) + E0; + *N = rho0 - rho * cos(theta) + N0; + + return; +} + + + + +/* @func GPS_Math_LambertCC_EN_To_LatLon ********************************** +** +** Convert Lambert Conformal Conic easting and northing to latitude and +** longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi1 [double] standard latitude (parallel) 1 (deg) +** @param [r] phi2 [double] standard latitude (parallel) 2 (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_LambertCC_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi1, double phi2, + double phi0, double M0, double E0, + double N0, double a, double b) +{ + double po2; + double po4; + double a2; + double b2; + double phi0s; + double e; + double esq; + double ed2; + double ess; + double t0; + double t1; + double t2; + double m1; + double m2; + double phi1s; + double phi1c; + double phi2s; + double phi2c; + double n; + double F; + double Fa; + double rho; + double rho0; + double phis; + double t; + double theta; + + double dx; + double dy; + double rhom; + double lat; + double tlat; + double tol; + + + + phi0 = GPS_Math_Deg_To_Rad(phi0); + phi1 = GPS_Math_Deg_To_Rad(phi1); + phi2 = GPS_Math_Deg_To_Rad(phi2); + M0 = GPS_Math_Deg_To_Rad(M0); + + + po2 = (double)GPS_PI / (double)2.0; + po4 = (double)GPS_PI / (double)4.0; + a2 = a*a; + b2 = b*b; + esq = (a2-b2)/a2; + e = pow(esq,(double)0.5); + ed2 = e / (double)2.0; + + phi0s = sin(phi0); + ess = e * phi0s; + t0 = tan(po4-phi0/(double)2.0) / pow(((double)1.0-ess) / + ((double)1.0+ess),ed2); + + + phi1s = sin(phi1); + phi1c = cos(phi1); + ess = e * phi1s; + m1 = phi1c / pow(((double)1.0-ess*ess),(double)0.5); + t1 = tan(po4-phi1/(double)2.0) / pow(((double)1.0-ess) / + ((double)1.0+ess),ed2); + + if(fabs(phi1-phi2)>1.0e-10) + { + phi2s = sin(phi2); + phi2c = cos(phi2); + ess = e * phi2s; + m2 = phi2c / pow(((double)1.0-ess*ess),(double)0.5); + t2 = tan(po4-phi2/(double)2.0) / pow(((double)1.0-ess) / + ((double)1.0+ess),ed2); + n = log(m1/m2) / log(t1/t2); + } + else + n = phi1s; + + F = m1 / (n*pow(t1,n)); + Fa = F*a; + + rho0 = pow(t0,n) * Fa; + + tlat = theta = (double)0.0; + tol = (double)4.85e-10; + + dx = E - E0; + dy = N - N0; + rhom = rho0 - dy; + rho = pow(dx*dx + rhom*rhom,(double)0.5); + + if(n<0.0) + { + rhom *= (double)-1.0; + dy *= (double)-1.0; + dx *= (double)-1.0; + rho *= (double)-1.0; + } + + if(rho) + { + theta = atan2(dx,rhom); + t = pow(rho/Fa,(double)1.0/n); + lat = po2 - (double)2.0*atan(t); + while(fabs(lat-tlat)>tol) + { + tlat = lat; + phis = sin(lat); + ess = e * phis; + lat = po2 - (double)2.0 * atan(t*pow(((double)1.0-ess) / + ((double)1.0+ess), + e / (double)2.0)); + } + *phi = lat; + *lambda = theta/n + M0; + + if(*phi>po2) + *phi=po2; + else if(*phi<-po2) + *phi=-po2; + if(*lambda>GPS_PI) + *lambda -= (double)GPS_PI * (double)2.0; + if(*lambda<-GPS_PI) + *lambda += (double)GPS_PI * (double)2.0; + + if(*lambda>GPS_PI) + *lambda = GPS_PI; + else if(*lambda<-GPS_PI) + *lambda = -GPS_PI; + } + else + { + if(n>0.0) + *phi = po2; + else + *phi = -po2; + *lambda = M0; + } + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_Miller_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Miller Cylindrical projection easting and +** northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Miller_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, + double N0, double a, double b) +{ + double a2; + double b2; + double R; + double e2; + double e4; + double e6; + double p2; + double po2; + double phis; + double dlam; + + + phi = GPS_Math_Deg_To_Rad(phi); + lambda = GPS_Math_Deg_To_Rad(lambda); + M0 = GPS_Math_Deg_To_Rad(M0); + + po2 = (double)GPS_PI / (double)2.0; + p2 = (double)GPS_PI * (double)2.0; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e4*e2; + + R = a*((double)1.0-e2/(double)6.0-(double)17.0*e4/(double)360.0- + (double)67.0*e6/(double)3024.0); + + if(M0>GPS_PI) + M0 -= p2; + + phis = sin((double)0.8 * phi); + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam-=p2; + if(dlam<-GPS_PI) + dlam+=p2; + + *E = R*dlam+E0; + *N = (R/(double)1.6) * log(((double)1.0+phis) / ((double)1.0-phis)) + N0; + + return; +} + + + + +/* @func GPS_Math_Miller_EN_To_LatLon ********************************** +** +** Convert latitude and longitude to Miller Cylindrical projection easting and +** northing +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Miller_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b) +{ + double a2; + double b2; + double R; + double e; + double e2; + double e4; + double e6; + double p2; + double po2; + double dx; + double dy; + + dx = E - E0; + dy = N - N0; + + M0 = GPS_Math_Deg_To_Rad(M0); + + po2 = (double)GPS_PI / (double)2.0; + p2 = (double)GPS_PI * (double)2.0; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e4*e2; + e = pow(e2,(double)0.5); + + R = a*((double)1.0-e2/(double)6.0-(double)17.0*e4/(double)360.0- + (double)67.0*e6/(double)3024.0); + if(M0>GPS_PI) + M0 -= p2; + + *phi = atan(sinh((double)0.8*dy/R)) / (double)0.8; + *lambda = M0+dx/R; + + if(*phi>po2) + *phi=po2; + else if (*phi<-po2) + *phi=-po2; + + if(*lambda>GPS_PI) + *lambda-=p2; + if(*lambda<-GPS_PI) + *lambda+=p2; + + if(*lambda>GPS_PI) + *lambda=GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_Bonne_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Bonne pseudoconic equal area projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Bonne_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, double E0, + double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e6; + double M1; + double m1; + double c0; + double c1; + double c2; + double c3; + double j; + double te4; + double E1; + double E2; + double E3; + double E4; + double x; + double phi0s; + double lat; + double phi0c; + double phi0s2; + double phi0s4; + double phi0s6; + double as; + + double phis; + double phic; + double phis2; + double phis4; + double phis6; + double dlam; + double mm; + double MM; + double rho; + double EE; + double tol; + + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + phi0 = GPS_Math_Deg_To_Rad(phi0); + M0 = GPS_Math_Deg_To_Rad(M0); + + phi0s = sin(phi0); + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(M0>GPS_PI) + M0 -= p2; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + + j = (double)45.0*e6/(double)1024.0; + te4 = (double)3.0 * e4; + c0 = (double)1.0-e2/(double)4.0-te4/(double)64.0-(double)5.0*e6/ + (double)256.0; + c1 = (double)3.0*e2/(double)8.0+te4/(double)32.0+j; + c2 = (double)15.0*e4/(double)256.0+j; + c3 = (double)35.0*e6/(double)3072.0; + + phi0c = cos(phi0); + m1 = phi0c/ pow(((double)1.0-e2*phi0s*phi0s),(double)0.5); + lat = c0 * phi0; + + phi0s2 = c1 * sin((double)2.0*phi0); + phi0s4 = c2 * sin((double)4.0*phi0); + phi0s6 = c3 * sin((double)6.0*phi0); + M1 = a*(lat-phi0s2+phi0s4-phi0s6); + + x = pow((double)1.0-e2,(double)0.5); + E1 = ((double)1.0-x) / ((double)1.0+x); + E2 = E1*E1; + E3 = E2*E1; + E4 = E3*E1; + + if(!phi0s) + as = (double)0.0; + else + as = a*m1/phi0s; + + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + + phis = sin(phi); + phic = cos(phi); + + tol = (double)0.0001; + if(!(phi-phi0) && (((po2-tol)GPS_PI) + M0 -= p2; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + + j = (double)45.0*e6/(double)1024.0; + te4 = (double)3.0 * e4; + c0 = (double)1.0-e2/(double)4.0-te4/(double)64.0-(double)5.0*e6/ + (double)256.0; + c1 = (double)3.0*e2/(double)8.0+te4/(double)32.0+j; + c2 = (double)15.0*e4/(double)256.0+j; + c3 = (double)35.0*e6/(double)3072.0; + + phi0c = cos(phi0); + m1 = phi0c/ pow(((double)1.0-e2*phi0s*phi0s),(double)0.5); + lat = c0 * phi0; + + phi0s2 = c1 * sin((double)2.0*phi0); + phi0s4 = c2 * sin((double)4.0*phi0); + phi0s6 = c3 * sin((double)6.0*phi0); + M1 = a*(lat-phi0s2+phi0s4-phi0s6); + + x = pow((double)1.0-e2,(double)0.5); + E1 = ((double)1.0-x) / ((double)1.0+x); + E2 = E1*E1; + E3 = E2*E1; + E4 = E3*E1; + A0 = (double)3.0*E1/(double)2.0-(double)27.0*E3/(double)32.0; + A1 = (double)21.0*E2/(double)16.0-(double)55.0*E4/(double)32.0; + A2 = (double)151.0*E3/(double)96.0; + A3 = (double)1097.0*E4/(double)512.0; + if(!phi0s) + as = (double)0.0; + else + as = a*m1/phi0s; + + + dx = E - E0; + dy = N - N0; + asdy = as - dy; + rho = pow(dx*dx+asdy*asdy,(double)0.5); + if(phi0<(double)0.0) + rho=-rho; + MM = as+M1-rho; + + mu = MM / (a*c0); + smu2 = A0 * sin((double)2.0*mu); + smu4 = A1 * sin((double)4.0*mu); + smu6 = A2 * sin((double)6.0*mu); + smu8 = A3 * sin((double)8.0*mu); + *phi = mu+smu2+smu4+smu6+smu8; + + tol = (double)0.00001; + if(((po2-tol)po2) + *phi = po2; + else if(*phi<-po2) + *phi = -po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda = GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_Cassini_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Cassini transverse cylindrical projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Cassini_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, + double E0, double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e6; + double AM0; + double c0; + double c1; + double c2; + double c3; + double om0; + double A0; + double A1; + double A2; + double A3; + double j; + double te4; + double phi0s2; + double phi0s4; + double phi0s6; + double lat; + double x; + double E1; + double E2; + double E3; + double E4; + + double phis; + double phic; + double phit; + double phis2; + double phis4; + double phis6; + double RD; + double dlam; + double NN; + double TT; + double WW; + double WW2; + double WW3; + double WW4; + double WW5; + double CC; + double MM; + + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi0 = GPS_Math_Deg_To_Rad(phi0); + phi = GPS_Math_Deg_To_Rad(phi); + M0 = GPS_Math_Deg_To_Rad(M0); + + + p2 = (double)GPS_PI * (double)2.; + po2 = (double)GPS_PI / (double)2.; + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + + te4 = (double)3.0 * e4; + j = (double)45. * e6 / (double)1024.; + c0 = (double)1.0-e2/(double)4.-te4/(double)64.-(double)5.*e6/(double)256.; + c1 = (double)3.*e2/(double)8.+te4/(double)32.+j; + c2 = (double)15.*e4/(double)256.+j; + c3 = (double)35.*e6/(double)3072.; + + lat = c0*phi0; + phi0s2 = c1 * sin((double)2.*phi0); + phi0s4 = c2 * sin((double)4.*phi0); + phi0s6 = c3 * sin((double)6.*phi0); + AM0 = a * (lat-phi0s2+phi0s4-phi0s6); + + om0 = (double)1.0 - e2; + x = pow(om0,(double)0.5); + E1 = ((double)1.0 - x) / ((double)1.0 + x); + E2 = E1*E1; + E3 = E1*E2; + E4 = E1*E3; + A0 = (double)3.*E1/(double)2.-(double)27.*E3/(double)32.; + A1 = (double)21.*E2/(double)16.-(double)55.*E4/(double)32.; + A2 = (double)151.*E3/(double)96.; + A3 = (double)1097.*E4/(double)512.; + + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + + phis = sin(phi); + phic = cos(phi); + phit = tan(phi); + RD = pow((double)1.-e2*phis*phis,(double).5); + NN = a/RD; + TT = phit*phit; + WW = dlam*phic; + WW2 = WW*WW; + WW3 = WW*WW2; + WW4 = WW*WW3; + WW5 = WW*WW4; + CC = e2*phic*phic/om0; + lat = c0*phi; + phis2 = c1 * sin((double)2.*phi); + phis4 = c2 * sin((double)4.*phi); + phis6 = c3 * sin((double)6.*phi); + MM = a * (lat-phis2+phis4-phis6); + + *E = NN*(WW-(TT*WW3/(double)6.)-((double)8.-TT+(double)8.*CC)* + (TT*WW5/(double)120.)) + E0; + *N = MM-AM0+NN*phit*((WW2/(double)2.)+((double)5.-TT+(double)6.*CC) * + WW4/(double)24.) + N0; + return; +} + + + + +/* @func GPS_Math_Cassini_EN_To_LatLon ********************************** +** +** Convert Cassini transverse cylindrical easting and northing projection +** to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Cassini_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b) + +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e6; + double AM0; + double c0; + double c1; + double c2; + double c3; + double om0; + double A0; + double A1; + double A2; + double A3; + double j; + double te4; + double phi0s2; + double phi0s4; + double phi0s6; + double lat; + double x; + double E1; + double E2; + double E3; + double E4; + + double dx; + double dy; + double mu; + double mus2; + double mus4; + double mus6; + double mus8; + double M1; + double phi1; + double phi1s; + double phi1c; + double phi1t; + double T; + double T1; + double N1; + double R1; + double RD; + double DD; + double D2; + double D3; + double D4; + double D5; + double tol; + + M0 = GPS_Math_Deg_To_Rad(M0); + phi0 = GPS_Math_Deg_To_Rad(phi0); + + p2 = (double)GPS_PI * (double)2.; + po2 = (double)GPS_PI / (double)2.; + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + + te4 = (double)3.0 * e4; + j = (double)45. * e6 / (double)1024.; + c0 = (double)1.0-e2/(double)4.-te4/(double)64.-(double)5.*e6/(double)256.; + c1 = (double)3.*e2/(double)8.+te4/(double)32.+j; + c2 = (double)15.*e4/(double)256.+j; + c3 = (double)35.*e6/(double)3072.; + + lat = c0*phi0; + phi0s2 = c1 * sin((double)2.*phi0); + phi0s4 = c2 * sin((double)4.*phi0); + phi0s6 = c3 * sin((double)6.*phi0); + AM0 = a * (lat-phi0s2+phi0s4-phi0s6); + + om0 = (double)1.0 - e2; + x = pow(om0,(double)0.5); + E1 = ((double)1.0 - x) / ((double)1.0 + x); + E2 = E1*E1; + E3 = E1*E2; + E4 = E1*E3; + A0 = (double)3.*E1/(double)2.-(double)27.*E3/(double)32.; + A1 = (double)21.*E2/(double)16.-(double)55.*E4/(double)32.; + A2 = (double)151.*E3/(double)96.; + A3 = (double)1097.*E4/(double)512.; + + + + tol = (double)1.e-5; + + dx = E - E0; + dy = N - N0; + M1 = AM0 + dy; + mu = M1 / (a*c0); + mus2 = A0 * sin((double)2.*mu); + mus4 = A1 * sin((double)4.*mu); + mus6 = A2 * sin((double)6.*mu); + mus8 = A3 * sin((double)8.*mu); + phi1 = mu + mus2 + mus4 + mus6 + mus8; + + if((((po2-tol)po2) + *phi=po2; + else if(*phi<-po2) + *phi=-po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda=GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + } + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_Cylea_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Cylindrical equal area projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Cylea_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, + double E0, double N0, double a, double b) +{ + double a2; + double b2; + double e; + double e2; + double e4; + double e6; + double k0; + double ak0; + double k2; + double c0; + double c1; + double c2; + double p2; + double po2; + double phi0s; + double phi0c; + + double dlam; + double qq; + double x; + double phis; + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi0 = GPS_Math_Deg_To_Rad(phi0); + phi = GPS_Math_Deg_To_Rad(phi); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.; + po2 = (double)GPS_PI / (double)2.; + + if(M0>GPS_PI) + M0-=p2; + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + e = pow(e2,(double).5); + c0 = e2/(double)3.+(double)31.*e4/(double)180.+(double)517.* + e6/(double)5040.; + c1 = (double)23.*e4/(double)360.+(double)251.*e6/(double)3780.; + c2 = (double)761.*e6/(double)45360.; + + phi0s = sin(phi0); + phi0c = cos(phi0); + k0 = phi0c / pow((double)1.-e2*phi0s*phi0s,(double).5); + ak0 = a*k0; + k2 = k0 * (double)2.; + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam-=p2; + if(dlam<-GPS_PI) + dlam+=p2; + + phis = sin(phi); + x = e * phis; + qq = ((double)1.-e2)*(phis/((double)1.-x*x)-((double)1./((double)2.*e))* + log(((double)1.-x)/((double)1.+x))); + *E = ak0 * dlam + E0; + *N = a * qq / k2 + N0; + + return; +} + + + + +/* @func GPS_Math_Cylea_EN_To_LatLon ********************************** +** +** Convert Cylindrical equal area easting and northing projection +** to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Cylea_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b) + +{ + double a2; + double b2; + double e; + double e2; + double e4; + double e6; + double k0; + double ak0; + double k2; + double c0; + double c1; + double c2; + double p2; + double po2; + double phi0s; + double phi0c; + + double dx; + double dy; + double qp; + double bt; + double phis; + double i; + double x; + double bs2; + double bs4; + double bs6; + + + phi0 = GPS_Math_Deg_To_Rad(phi0); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.; + po2 = (double)GPS_PI / (double)2.; + + if(M0>GPS_PI) + M0-=p2; + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + e = pow(e2,(double).5); + c0 = e2/(double)3.+(double)31.*e4/(double)180.+(double)517.* + e6/(double)5040.; + c1 = (double)23.*e4/(double)360.+(double)251.*e6/(double)3780.; + c2 = (double)761.*e6/(double)45360.; + + phi0s = sin(phi0); + phi0c = cos(phi0); + k0 = phi0c / pow((double)1.-e2*phi0s*phi0s,(double).5); + ak0 = a*k0; + k2 = k0 * (double)2.; + + dx = E - E0; + dy = N - N0; + phis = sin(po2); + x = e*phis; + qp = ((double)1.-e2)*(phis/((double)1.-x*x)-((double)1./((double)2.*e))* + log(((double)1.-x)/((double)1.+x))); + i = k2*dy/(a*qp); + if(i>(double)1.) + i=(double)1.; + else if(i<(double)-1.) + i=(double)-1.; + bt = asin(i); + bs2 = c0 * sin((double)2.*bt); + bs4 = c1 * sin((double)4.*bt); + bs6 = c2 * sin((double)6.*bt); + + *phi = bt+bs2+bs4+bs6; + *lambda = M0 + dx/ak0; + + if(*phi>po2) + *phi=po2; + else if(*phi<-po2) + *phi=-po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda=GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_EckertIV_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Eckert IV equal area elliptical +** pseudocylindrical projection easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_EckertIV_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, double N0, + double a, double b) +{ + double a2; + double b2; + double e2; + double e4; + double e6; + double Ra0; + double Ra1; + double po2; + double p2; + + double Ra; + + double phis; + double theta; + double dtheta; + double thetas; + double thetac; + double n; + double dlam; + double tol; + + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.; + po2 = (double)GPS_PI / (double)2.; + + if(M0>GPS_PI) + M0-=p2; + + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2) / a2; + e4 = e2*e2; + e6 = e2*e4; + Ra = a*((double)1.-e2/(double)6.-(double)17.*e4/(double)360.- + (double)67.*e6/(double)3024.); + Ra0 = Ra * (double)0.4222382; + Ra1 = Ra * (double)1.3265004; + + theta = phi / (double)2.; + dtheta = (double)1.; + tol = (double)4.85e-10; + phis = sin(phi); + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + + while(fabs(dtheta)>tol) + { + thetas = sin(theta); + thetac = cos(theta); + n = theta+thetas*thetac+(double)2.*thetas; + dtheta = -(n-((double)2.+po2)*phis) / + ((double)2.*thetac*((double)1.+thetac)); + theta += dtheta; + } + + *E = Ra0*dlam*((double)1.+cos(theta))+E0; + *N = Ra1*sin(theta)+N0; + + return; +} + + + + +/* @func GPS_Math_EckertIV_EN_To_LatLon ********************************** +** +** Convert Eckert IV equal area elliptical pseudocylindrical projection +** easting and northing to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_EckertIV_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b) +{ + double a2; + double b2; + double e2; + double e4; + double e6; + double Ra0; + double Ra1; + double po2; + double p2; + + double Ra; + double theta; + double thetas; + double thetac; + double n; + double dx; + double dy; + double i; + + + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.; + po2 = (double)GPS_PI / (double)2.; + + if(M0>GPS_PI) + M0-=p2; + + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2) / a2; + e4 = e2*e2; + e6 = e2*e4; + Ra = a*((double)1.-e2/(double)6.-(double)17.*e4/(double)360.- + (double)67.*e6/(double)3024.); + Ra0 = Ra * (double)0.4222382; + Ra1 = Ra * (double)1.3265004; + + dx = E - E0; + dy = N - N0; + i = dy/Ra1; + if(i>(double)1.) + i=(double)1.; + else if(i<(double)-1.) + i=(double)-1.; + + theta = asin(i); + thetas = sin(theta); + thetac = cos(theta); + n = theta+thetas*thetac+(double)2.*thetas; + + *phi = asin(n/((double)2. + po2)); + *lambda = M0 + dx / (Ra0*((double)1.+thetac)); + + if(*phi>po2) + *phi=po2; + else if(*phi<-po2) + *phi=-po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda=GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + + +/* @func GPS_Math_EckertVI_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Eckert VI equal area +** pseudocylindrical projection easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_EckertVI_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, double N0, + double a, double b) +{ + double a2; + double b2; + double e2; + double e4; + double e6; + double Ra; + double Rsq; + double IRa; + double po2; + double p2; + + double phis; + double theta; + double dtheta; + double dlam; + double tol; + + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.; + po2 = (double)GPS_PI / (double)2.; + + if(M0>GPS_PI) + M0-=p2; + + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2) / a2; + e4 = e2*e2; + e6 = e2*e4; + Ra = a*((double)1.-e2/(double)6.-(double)17.*e4/(double)360.- + (double)67.*e6/(double)3024.); + Rsq = Ra/pow((double)2.+GPS_PI,(double).5); + IRa = (double)1./Rsq; + + phis = sin(phi); + theta = phi; + dtheta = (double)1.; + tol = (double)4.85e-10; + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + + while(fabs(dtheta)>tol) + { + dtheta = -(theta+sin(theta)-((double)1.+po2)*phis) / + ((double)1.+cos(theta)); + theta += dtheta; + } + + *E = Rsq*dlam*((double)1.+cos(theta))+E0; + *N = (double)2.*Rsq*theta+N0; + + return; +} + + + + +/* @func GPS_Math_EckertVI_EN_To_LatLon ********************************** +** +** Convert Eckert VI equal area pseudocylindrical projection +** easting and northing to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_EckertVI_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b) +{ + double a2; + double b2; + double e2; + double e4; + double e6; + double Rsq; + double IRa; + double po2; + double p2; + + double Ra; + double theta; + double dx; + double dy; + double i; + + + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.; + po2 = (double)GPS_PI / (double)2.; + + if(M0>GPS_PI) + M0-=p2; + + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2) / a2; + e4 = e2*e2; + e6 = e2*e4; + Ra = a*((double)1.-e2/(double)6.-(double)17.*e4/(double)360.- + (double)67.*e6/(double)3024.); + Rsq = Ra/pow((double)2.+GPS_PI,(double).5); + IRa = (double)1./Rsq; + + + dx = E - E0; + dy = N - N0; + theta = IRa * dy / (double)2.; + i = (theta+sin(theta)) / ((double)1.+po2); + if(i>(double)1.) + *phi = po2; + else if(i<(double)-1.) + *phi = -po2; + else + *phi= asin(i); + *lambda = M0 + IRa * dx / ((double)1.+cos(theta)); + + if(*phi>po2) + *phi=po2; + else if(*phi<-po2) + *phi=-po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda=GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + + +/* @func GPS_Math_Cyled_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to cylindrical equidistant projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Cyled_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, double E0, + double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e6; + double Ra; + double Rac; + double phi0c; + + double dlam; + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + phi0 = GPS_Math_Deg_To_Rad(phi0); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(M0>GPS_PI) + M0 -= p2; + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + + Ra = a*((double)1.-e2/(double)6.-(double)17.*e4/(double)360.- + (double)67.*e6/(double)3024.); + phi0c = cos(phi0); + Rac = Ra * phi0c; + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + + *E = Rac * dlam + E0; + *N = Ra * phi + N0; + + return; +} + + + + +/* @func GPS_Math_Cyled_EN_To_LatLon ********************************** +** +** Convert cylindrical equidistant easting and northing projection +** to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Cyled_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e6; + double Ra; + double Rac; + double phi0c; + + double dx; + double dy; + + + phi0 = GPS_Math_Deg_To_Rad(phi0); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(M0>GPS_PI) + M0 -= p2; + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + + Ra = a*((double)1.-e2/(double)6.-(double)17.*e4/(double)360.- + (double)67.*e6/(double)3024.); + phi0c = cos(phi0); + Rac = Ra * phi0c; + + dx = E - E0; + dy = N - N0; + + if(!Rac) + *lambda = (double)0.; + else + *lambda = M0 + dx / Rac; + + *phi = dy/Ra; + + if(*phi>po2) + *phi = po2; + else if(*phi<-po2) + *phi = -po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda = GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_VderGrinten_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Van der Grinten polyconic projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_VderGrinten_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, + double N0, double a, double b) +{ + double po2; + double p2; + double a2; + double b2; + double e2; + double e4; + double e6; + double Ra; + double pRa; + + double gg; + double pp; + double pp2; + double gm0; + double ppa; + double thetai; + double theta; + double thetas; + double thetac; + double qq; + double tol; + double aa; + double aa2; + double dlam; + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(M0>GPS_PI) + M0 -= p2; + + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + + Ra = a*((double)1.-e2/(double)6.-(double)17.*e4/(double)360.-(double)67.* + e6/(double)3024.); + pRa = (double)GPS_PI * Ra; + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + + tol = (double)1.0e-5; + + if(!phi) + { + *N = (double)0.0; + *E = Ra*dlam+E0; + } + else if(!dlam || (((po2-tol)(double)1.) + thetai=(double)1.; + else if(thetai<(double)-1.) + thetai=(double)-1.; + + theta = asin(thetai); + *E = 0; + *N = pRa * tan(theta/(double)2.) * N0; + if(phi<(double)0.0) + *N *= (double)-1.; + } + else + { + aa = (double).5*fabs((double)GPS_PI/dlam - dlam/(double)GPS_PI); + thetai = fabs(((double)2./(double)GPS_PI) * phi); + if(thetai>(double)1.) + thetai=(double)1.; + else if(thetai<(double)-1.) + thetai=(double)-1.; + + theta = asin(thetai); + thetas = sin(theta); + thetac = cos(theta); + gg = thetac/(thetas+thetac-(double)1.); + pp = gg*((double)2./thetas-(double)1.); + aa2 = aa*aa; + pp2 = pp*pp; + gm0 = gg-pp2; + ppa = pp2+aa2; + qq = aa2+gg; + *E = pRa*(aa*gm0+pow(aa2*gm0*gm0-ppa*(gg*gg-pp2),(double).5))/ppa+E0; + if(dlam<(double)0.0) + *E *= (double)-1.; + *N = pRa*(pp*qq-aa*pow((aa2+(double)1.)*ppa-qq*qq,(double).5))/ppa+N0; + if(phi<(double)0.0) + *N *= (double)-1.; + } + + return; +} + + + + +/* @func GPS_Math_VderGrinten_EN_To_LatLon ********************************** +** +** Convert Van der Grinten polyconic easting and northing projection +** to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_VderGrinten_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b) +{ + double po2; + double p2; + double a2; + double b2; + double e2; + double e4; + double e6; + double Ra; + double pRa; + + double dx; + double dy; + double xx; + double xx2; + double yy; + double yy2; + double tyy2; + double xpy; + double c1; + double c2; + double c3; + double c3c3; + double co; + double dd; + double a1; + double m1; + double i; + double theta; + + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(M0>GPS_PI) + M0 -= p2; + + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + + Ra = a*((double)1.-e2/(double)6.-(double)17.*e4/(double)360.-(double)67.* + e6/(double)3024.); + pRa = (double)GPS_PI * Ra; + + + dx = E - E0; + dy = N - N0; + xx = dx/pRa; + yy = dy/pRa; + xx2 = xx*xx; + yy2 = yy*yy; + xpy = xx2+yy2; + tyy2 = yy2*(double)2.; + + if(!N) + *phi=(double)0.0; + else + { + c1 = -fabs(yy)*((double)1.+xpy); + c2 = c1-tyy2+xx2; + c3 = (double)-2.*c1+(double)1.+tyy2+xpy*xpy; + co = c2/((double)3.*c3); + c3c3 = c3*c3; + dd = yy2/c3+(((double)2.*c2*c2*c2)/(c3c3*c3)-((double)9.*c1*c2)/ + c3c3)/(double)27.; + a1 = (c1-c2*co)/c3; + m1 = (double)2.* pow(-((double)1./(double)3.)*a1,(double).5); + i = (double)3.*dd/(a1*m1); + if((i>(double)1.)||(i<(double)-1.)) + *phi=po2; + else + { + theta = ((double)1./(double)3.)*acos((double)3.*dd/(a1*m1)); + *phi = (double)GPS_PI*(-m1*cos(theta+(double)GPS_PI/(double)3.)- + co); + } + } + + if(N<(double)0.0) + *phi *= (double)-1.0; + + if(!xx) + *lambda = M0; + else + *lambda = (double)GPS_PI * (xpy-(double)1.+ + pow((double)1.+((double)2.*xx2-tyy2)+xpy*xpy,(double).5)) / + ((double)2.*xx) + M0; + if(*phi>po2) + *phi = po2; + else if(*phi<-po2) + *phi = -po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda = GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_Bonne_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Bonne pseudoconic equal area projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi1 [double] latitude of true scale (deg) +** @param [r] lambda1 [double] longitude from pole (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_PolarSt_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi1, double lambda1, + double E0, double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4=(double)0.; + double e; + double eo2; + double sh; + double mc; + double tc=(double)0.; + double amc=(double)0.; + double ta; + double phi1s; + double phi1c; + double es; + double op; + double om; + double pe; + double polat; + double polon; + + double dlam; + double phis; + double t; + double rho; + + + lambda1 = GPS_Math_Deg_To_Rad(lambda1); + phi1 = GPS_Math_Deg_To_Rad(phi1); + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + + ta = a * (double)2.0; + if(lambda1>GPS_PI) + lambda1 -= p2; + if(phi1<(double)0.0) + { + sh=(double)1.0; + polat = -phi1; + polon = -lambda1; + } + else + { + sh=(double)0.0; + polat = phi1; + polon = lambda1; + } + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e = pow(e2,(double).5); + eo2 = e/(double)2.; + + if(fabs(fabs(polat)-po2)>(double)1.0e-10) + { + phi1s = sin(polat); + phi1c = cos(polat); + es = e*phi1s; + pe = pow(((double)1.-es)/((double)1.+es),eo2); + mc = phi1c / pow((double)1.-es*es,(double).5); + amc = mc * a; + tc = tan(((double)GPS_PI/(double)4.)-polat/(double)2.) / pe; + } + else + { + op = (double)1. + e; + om = (double)1. - e; + e4 = pow(pow(op,op)*pow(om,om),(double).5); + } + + + + if(fabs(fabs(phi)-po2)<(double)1.0e-10) + *E = *N = (double)0.0; + else + { + if(sh) + { + phi *= (double)-1.0; + lambda *= (double)-1.0; + } + + dlam = lambda - polon; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + phis = sin(phi); + es = e * phis; + pe = pow(((double)1.-es)/((double)1.+es),eo2); + t = tan(((double)GPS_PI/(double)4.)-phi/(double)2.) / pe; + + if(fabs(fabs(polat)-po2)>(double)1.0e-10) + rho = amc * t / tc; + else + rho = ta * t / e4; + *E = rho * sin(dlam) + E0; + + if(sh) + { + *E *= (double)-1.; + *N = rho * cos(dlam) + N0; + } + else + *N = -rho * cos(dlam) + N0; + } + + return; +} + + + + +/* @func GPS_Math_PolarSt_EN_To_LatLon ********************************** +** +** Convert Polar Stereographic easting and northing projection +** to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi1 [double] latitude of true scale (deg) +** @param [r] lambda1 [double] longitude from pole (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_PolarSt_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi1, double lambda1, + double E0, double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4=(double)0.; + double e; + double eo2; + double sh; + double mc; + double tc=(double)0.; + double amc=(double)0.; + double ta; + double phi1s; + double phi1c; + double es; + double op; + double om; + double pe; + double polat; + double polon; + + double dx; + double dy; + double t; + double rho; + double PHI; + double PHIS; + double TPHI; + + + lambda1 = GPS_Math_Deg_To_Rad(lambda1); + phi1 = GPS_Math_Deg_To_Rad(phi1); + + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + + ta = a * (double)2.0; + if(lambda1>GPS_PI) + lambda1 -= p2; + if(phi1<(double)0.0) + { + sh=(double)1.0; + polat = -phi1; + polon = -lambda1; + } + else + { + sh=(double)0.0; + polat = phi1; + polon = lambda1; + } + + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e = pow(e2,(double).5); + eo2 = e/(double)2.; + + if(fabs(fabs(polat)-po2)>(double)1.0e-10) + { + phi1s = sin(polat); + phi1c = cos(polat); + es = e*phi1s; + pe = pow(((double)1.-es)/((double)1.+es),eo2); + mc = phi1c / pow((double)1.-es*es,(double).5); + amc = mc * a; + tc = tan(((double)GPS_PI/(double)4.)-polat/(double)2.) / pe; + } + else + { + op = (double)1. + e; + om = (double)1. - e; + e4 = pow(pow(op,op)*pow(om,om),(double).5); + } + + + dx = E - E0; + dy = N - N0; + if(!dx && !dy) + { + *phi = po2; + *lambda = polon; + } + else + { + if(sh) + { + dx *= (double)-1.; + dy *= (double)-1.; + } + rho = pow(dx*dx+dy*dy,(double).5); + if(fabs(fabs(polat)-po2)>(double)1.0e-10) + t = rho * tc / amc; + else + t = rho * e4 / ta; + TPHI = (double)0.0; + PHI = po2 - (double)2.*atan(t); + while(fabs(PHI-TPHI)>(double)1.0e-10) + { + TPHI=PHI; + PHIS = sin(PHI); + es = e * PHIS; + pe = pow(((double)1.-es)/((double)1.+es),eo2); + PHI = po2 - (double)2. * atan(t*pe); + } + *phi = PHI; + *lambda = polon + atan2(dx,-dy); + + if(*phi>po2) + *phi = po2; + else if(*phi<-po2) + *phi = -po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda = GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + } + if(sh) + { + *phi *= (double)-1.; + *lambda *= (double)1.; + } + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_Mollweide_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Mollweide projection easting and +** northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Mollweide_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, + double N0, double a, double b) +{ + double a2; + double b2; + double e2; + double e4; + double e6; + double p2; + double po2; + double Ra; + double sRa2; + double sRa8; + + double ps; + double dlam; + double theta; + double thetap; + double d; + double tol; + + phi = GPS_Math_Deg_To_Rad(phi); + lambda = GPS_Math_Deg_To_Rad(lambda); + M0 = GPS_Math_Deg_To_Rad(M0); + + po2 = (double)GPS_PI / (double)2.0; + p2 = (double)GPS_PI * (double)2.0; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e4*e2; + + Ra = a*((double)1.0-e2/(double)6.0-(double)17.0*e4/(double)360.0- + (double)67.0*e6/(double)3024.0); + sRa2 = pow((double)2.,(double).5) * Ra; + sRa8 = pow((double)8.,(double).5) * Ra; + + if(M0>GPS_PI) + M0 -= p2; + + ps = sin(phi) * (double)GPS_PI; + d = (double)0.1745329; + tol = (double)4.85e-10; + thetap = phi; + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam-=p2; + if(dlam<-GPS_PI) + dlam+=p2; + + while(fabs(d)>tol) + { + d = -(thetap+sin(thetap)-ps)/((double)1.+cos(thetap)); + thetap += d; + } + theta = thetap / (double)2.; + *E = (sRa8/(double)GPS_PI) * dlam * cos(theta) + E0; + *N = sRa2 * sin(theta) + N0; + + return; +} + + + + +/* @func GPS_Math_Mollweide_EN_To_LatLon ********************************** +** +** Convert latitude and longitude to Mollweide projection easting and +** northing +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Mollweide_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b) +{ + double a2; + double b2; + double e2; + double e4; + double e6; + double p2; + double po2; + double Ra; + double sRa2; + double sRa8; + + double dx; + double dy; + double theta=(double)0.; + double tt; + double i; + + M0 = GPS_Math_Deg_To_Rad(M0); + + po2 = (double)GPS_PI / (double)2.0; + p2 = (double)GPS_PI * (double)2.0; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e4*e2; + + Ra = a*((double)1.0-e2/(double)6.0-(double)17.0*e4/(double)360.0- + (double)67.0*e6/(double)3024.0); + sRa2 = pow((double)2.,(double).5) * Ra; + sRa8 = pow((double)8.,(double).5) * Ra; + + if(M0>GPS_PI) + M0 -= p2; + + dx = E - E0; + dy = N - N0; + i = dy/sRa2; + if(fabs(i)>(double)1.) + { + *phi = po2; + if(N<(double)0.0) + *phi *= (double)-1.; + } + else + { + theta = asin(i); + tt = theta * (double)2.; + *phi = asin((tt+sin(tt))/(double)GPS_PI); + if(*phi>po2) + *phi=po2; + else if (*phi<-po2) + *phi=-po2; + } + + if(fabs(fabs(*phi)-po2)<(double)1.0e-10) + *lambda = M0; + else + *lambda = M0 + (double)GPS_PI * dx / (sRa8 * cos(theta)); + + + if(*lambda>GPS_PI) + *lambda-=p2; + if(*lambda<-GPS_PI) + *lambda+=p2; + + if(*lambda>GPS_PI) + *lambda=GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_Orthog_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to orthographic projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] lambda0 [double] longitude of origin (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Orthog_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double lambda0, + double E0, double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e6; + double Ra; + double phi0s; + double phi0c; + + double phis; + double phic; + double dlam; + double clc; + double cc; + + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + phi0 = GPS_Math_Deg_To_Rad(phi0); + lambda0 = GPS_Math_Deg_To_Rad(lambda0); + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(lambda0>GPS_PI) + lambda0 -= p2; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + Ra = a * ((double)1.-e2/(double)6.-(double)17.*e4/(double)360.-(double)67.* + e6/(double)3024.); + phi0s = sin(phi0); + phi0c = cos(phi0); + + dlam = lambda - lambda0; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + + + phis = sin(phi); + phic = cos(phi); + clc = phic * cos(dlam); + cc = phi0s * phis + phi0c * clc; + + *E = Ra * phic * sin(dlam) + E0; + *N = Ra * (phi0c * phis - phi0s * clc) + N0; + + return; +} + + + + +/* @func GPS_Math_Orthog_EN_To_LatLon ********************************** +** +** Convert Orthogonal easting and northing projection +** to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] lambda0 [double] longitude of origin (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Orthog_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double lambda0, + double E0, double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e6; + double Ra; + double phi0s; + double phi0c; + + double dx; + double dy; + double rho; + double adod; + double ror; + double cc; + double ccs; + double ccc; + + + + + phi0 = GPS_Math_Deg_To_Rad(phi0); + lambda0 = GPS_Math_Deg_To_Rad(lambda0); + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(lambda0>GPS_PI) + lambda0 -= p2; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + Ra = a * ((double)1.-e2/(double)6.-(double)17.*e4/(double)360.-(double)67.* + e6/(double)3024.); + phi0s = sin(phi0); + phi0c = cos(phi0); + + + dx = E - E0; + dy = N - N0; + adod = atan(dx/dy); + rho = pow(dx*dx+dy*dy,(double).5); + if(!rho) + { + *phi = phi0; + *lambda = lambda0; + } + else + { + ror = rho/Ra; + if(ror>(double)1.) + ror=(double)1.; + else if(ror<(double)-1.) + ror=(double)-1.; + cc = asin(ror); + ccs = sin(cc); + ccc = cos(cc); + *phi = asin(ccc*phi0s+(dy*ccs*phi0c/rho)); + if(phi0==po2) + *lambda = lambda0 - adod; + else if(phi0==-po2) + *lambda = lambda0 + adod; + else + *lambda = lambda0+atan(dx*ccs/(rho*phi0c*ccc-dy*phi0s*ccs)); + } + + if(*phi>po2) + *phi = po2; + else if(*phi<-po2) + *phi = -po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda = GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_Polycon_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Polyconic projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Polycon_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, + double E0, double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e6; + double AM0; + double c0; + double c1; + double c2; + double c3; + double j; + double te4; + double phi0s2; + double phi0s4; + double phi0s6; + + double phis; + double phis2; + double phis4; + double phis6; + double dlam; + double NN; + double NNot; + double MM; + double EE; + double lat; + + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + phi0 = GPS_Math_Deg_To_Rad(phi0); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(M0>GPS_PI) + M0 -= p2; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + + j = (double)45.0*e6/(double)1024.0; + te4 = (double)3.0 * e4; + c0 = (double)1.0-e2/(double)4.0-te4/(double)64.0-(double)5.0*e6/ + (double)256.0; + c1 = (double)3.0*e2/(double)8.0+te4/(double)32.0+j; + c2 = (double)15.0*e4/(double)256.0+j; + c3 = (double)35.0*e6/(double)3072.0; + + lat = c0 * phi0; + + phi0s2 = c1 * sin((double)2.0*phi0); + phi0s4 = c2 * sin((double)4.0*phi0); + phi0s6 = c3 * sin((double)6.0*phi0); + AM0 = a*(lat-phi0s2+phi0s4-phi0s6); + + + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + + phis = sin(phi); + + if(!phi) + { + *E = a * dlam + E0; + *N = -AM0 + N0; + } + else + { + NN = a / pow((double)1.-e2*phis*phis,(double).5); + NNot = NN / tan(phi); + lat = c0 * phi; + phis2 = c1 * sin((double)2.0*phi); + phis4 = c2 * sin((double)4.0*phi); + phis6 = c3 * sin((double)6.0*phi); + MM = a*(lat-phis2+phis4-phis6); + EE = dlam *phis; + *E = NNot * sin(EE) + E0; + *N = MM - AM0 + NNot * ((double)1.-cos(EE)) + N0; + } + + return; +} + + + + +/* @func GPS_Math_Polycon_EN_To_LatLon ********************************** +** +** Convert Polyconic easting and northing projection +** to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Polycon_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e6; + double AM0; + double c0; + double c1; + double c2; + double c3; + double j; + double te4; + double phi0s2; + double phi0s4; + double phi0s6; + + double dx; + double dy; + double dxoa; + double AA; + double BB; + double CC=(double)0.; + double PHIn; + double PHId; + double PHIs; + double PHI; + double PHIs2; + double PHIs4; + double PHIs6; + double Mn; + double Mnp; + double Ma; + double AAMa; + double mpb; + double AAmin; + double tol; + double lat; + + + phi0 = GPS_Math_Deg_To_Rad(phi0); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(M0>GPS_PI) + M0 -= p2; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + + j = (double)45.0*e6/(double)1024.0; + te4 = (double)3.0 * e4; + c0 = (double)1.0-e2/(double)4.0-te4/(double)64.0-(double)5.0*e6/ + (double)256.0; + c1 = (double)3.0*e2/(double)8.0+te4/(double)32.0+j; + c2 = (double)15.0*e4/(double)256.0+j; + c3 = (double)35.0*e6/(double)3072.0; + + lat = c0 * phi0; + + phi0s2 = c1 * sin((double)2.0*phi0); + phi0s4 = c2 * sin((double)4.0*phi0); + phi0s6 = c3 * sin((double)6.0*phi0); + AM0 = a*(lat-phi0s2+phi0s4-phi0s6); + + tol = (double)1.0e-12; + + dx = E - E0; + dy = N - N0; + dxoa = dx/a; + if((((-AM0-(double)1.)tol) + { + PHIs = sin(PHIn); + CC = pow((double)1.-e2*PHIs*PHIs,(double).5) * tan(PHIn); + PHI = PHIn * c0; + PHIs2 = c1 * sin((double)2.0*PHIn); + PHIs4 = c2 * sin((double)4.0*PHIn); + PHIs6 = c3 * sin((double)6.0*PHIn); + Mn = a*(PHI-PHIs2+PHIs4-PHIs6); + Mnp = c0 - (double)2.*c1*cos((double)2.*PHIn)+(double)4.*c2* + cos((double)4.*PHIn)-(double)6.*c3*cos((double)6.*PHIn); + Ma = Mn / a; + AAMa = AA * Ma; + mpb = Ma*Ma+BB; + AAmin = AA - Ma; + PHId = (AAMa*CC+AAmin-(double).5*mpb*CC)/ + (e2*PHIs2*(mpb-(double)2.*AAMa) / + (double)4.*CC+AAmin*(CC*Mnp-(double)2./PHIs2)-Mnp); + PHIn -= PHId; + } + *phi = PHIn; + + if(*phi>po2) + *phi = po2; + else if(*phi<-po2) + *phi = -po2; + + if((((po2-(double).00001)GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda = GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_Sinusoid_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to Sinusoidal projection easting and +** northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Sinusoid_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, + double N0, double a, double b) +{ + double a2; + double b2; + double e2; + double e4; + double e6; + double p2; + double po2; + double c0; + double c1; + double c2; + double c3; + double A1; + double A0; + double A2; + double A3; + double E1; + double E2; + double E3; + double E4; + double j; + double om0; + double som0; + + double phis; + double phis2; + double phis4; + double phis6; + double mm; + double MM; + double dlam; + + + phi = GPS_Math_Deg_To_Rad(phi); + lambda = GPS_Math_Deg_To_Rad(lambda); + M0 = GPS_Math_Deg_To_Rad(M0); + + po2 = (double)GPS_PI / (double)2.0; + p2 = (double)GPS_PI * (double)2.0; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e4*e2; + + j = (double)45.*e6/(double)1024.; + c0 = (double)1.-e2/(double)4.-(double)3.*e4/(double)64.-(double)5.* + e6/(double)256.; + c1 = (double)3.*e2/(double)8.+(double)3.*e4/(double)32.+j; + c2 = (double)15.*e4/(double)256.+j; + c3 = (double)35.*e6/(double)3072.; + om0 = (double)1. - e2; + som0 = pow(om0,(double).5); + E1 = ((double)1.-som0)/((double)1.+som0); + E2 = E1*E1; + E3 = E1*E2; + E4 = E1*E3; + A0 = (double)3.*E1/(double)2.-(double)27.*E3/(double)32.; + A1 = (double)21.*E2/(double)16.-(double)55.*E4/(double)32.; + A2 = (double)151.*E3/(double)96.; + A3 = (double)1097.*E4/(double)512.; + + if(M0>GPS_PI) + M0 -= p2; + + phis = sin(phi); + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam-=p2; + if(dlam<-GPS_PI) + dlam+=p2; + + mm = pow((double)1.-e2*phis*phis,(double).5); + phis2 = c1 * sin((double)2.*phi); + phis4 = c2 * sin((double)4.*phi); + phis6 = c3 * sin((double)6.*phi); + MM = a * (c0*phi-phis2+phis4-phis6); + + + + *E = a*dlam*cos(phi)/mm+E0; + *N = MM + N0; + + return; +} + + + + +/* @func GPS_Math_Sinusoid_EN_To_LatLon ********************************** +** +** Convert latitude and longitude to Sinusoidal projection easting and +** northing +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Sinusoid_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b) +{ + double a2; + double b2; + double e2; + double e4; + double e6; + double p2; + double po2; + double c0; + double c1; + double c2; + double c3; + double A1; + double A0; + double A2; + double A3; + double E1; + double E2; + double E3; + double E4; + double j; + double om0; + double som0; + + double dx; + double dy; + double mu; + double mu2s; + double mu4s; + double mu6s; + double mu8s; + double phis; + + + M0 = GPS_Math_Deg_To_Rad(M0); + + po2 = (double)GPS_PI / (double)2.0; + p2 = (double)GPS_PI * (double)2.0; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e4*e2; + + j = (double)45.*e6/(double)1024.; + c0 = (double)1.-e2/(double)4.-(double)3.*e4/(double)64.-(double)5.* + e6/(double)256.; + c1 = (double)3.*e2/(double)8.+(double)3.*e4/(double)32.+j; + c2 = (double)15.*e4/(double)256.+j; + c3 = (double)35.*e6/(double)3072.; + om0 = (double)1. - e2; + som0 = pow(om0,(double).5); + E1 = ((double)1.-som0)/((double)1.+som0); + E2 = E1*E1; + E3 = E1*E2; + E4 = E1*E3; + A0 = (double)3.*E1/(double)2.-(double)27.*E3/(double)32.; + A1 = (double)21.*E2/(double)16.-(double)55.*E4/(double)32.; + A2 = (double)151.*E3/(double)96.; + A3 = (double)1097.*E4/(double)512.; + + + dx = E - E0; + dy = N - N0; + + mu = dy/(c0*a); + mu2s = A0 * sin((double)2.*mu); + mu4s = A1 * sin((double)4.*mu); + mu6s = A2 * sin((double)6.*mu); + mu8s = A3 * sin((double)8.*mu); + *phi = mu + mu2s + mu4s + mu6s + mu8s; + + if(*phi>po2) + *phi=po2; + else if (*phi<-po2) + *phi=-po2; + + if((((po2-(double)1.0e-8)GPS_PI) + *lambda-=p2; + if(*lambda<-GPS_PI) + *lambda+=p2; + + if(*lambda>GPS_PI) + *lambda=GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_TCylEA_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to transverse cylindrical equal area +** projection easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_TCylEA_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, double E0, + double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e; + double e2; + double e4; + double e6; + double AM0; + double qp; + double om; + double oo; + double c0; + double c1; + double c2; + double c3; + double b0; + double b1; + double B2; + double b3; + double A0; + double A1; + double A2; + double sf; + double x; + double som; + double phis; + double j; + double te4; + double lat; + double phi0s2; + double phi0s4; + double phi0s6; + double E1; + double E2; + double E3; + double E4; + + double dlam; + double qq; + double qqo; + double bt; + double btc; + double PHI; + double PHIs2; + double PHIs4; + double PHIs6; + double bts2; + double bts4; + double bts6; + double PHIc; + double PHIcs; + double Mc; + + + + sf = (double)1.0; /* scale factor */ + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + phi0 = GPS_Math_Deg_To_Rad(phi0); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(M0>GPS_PI) + M0 -= p2; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + e = pow(e2,(double).5); + om = (double)1.-e2; + som = pow(om,(double).5); + oo = (double)1./((double)2.*e); + + phis = sin(po2); + x = e * phis; + qp = om*(phis/((double)1.-e2*phis*phis)-oo* + log(((double)1.-x)/((double)1.+x))); + + A0 = e2 / (double)3.+(double)31.*e4/(double)180.+(double)517.* + e6/(double)5040.; + A1 = (double)23.*e4/(double)360.+(double)251.*e6/(double)3780.; + A2 = (double)761.*e6/(double)45360.; + + E1 = ((double)1.0-som) / ((double)1.0+som); + E2 = E1*E1; + E3 = E2*E1; + E4 = E3*E1; + + b0 = (double)3.*E1/(double)2.-(double)27.*E3/(double)32.; + b1 = (double)21.*E2/(double)16.-(double)55.*E4/(double)32.; + B2 = (double)151.*E3/(double)96.; + b3 = (double)1097.*E4/(double)512.; + + + j = (double)45.0*e6/(double)1024.0; + te4 = (double)3.0 * e4; + c0 = (double)1.0-e2/(double)4.0-te4/(double)64.0-(double)5.0*e6/ + (double)256.0; + c1 = (double)3.0*e2/(double)8.0+te4/(double)32.0+j; + c2 = (double)15.0*e4/(double)256.0+j; + c3 = (double)35.0*e6/(double)3072.0; + + lat = c0 * phi0; + + phi0s2 = c1 * sin((double)2.0*phi0); + phi0s4 = c2 * sin((double)4.0*phi0); + phi0s6 = c3 * sin((double)6.0*phi0); + AM0 = a*(lat-phi0s2+phi0s4-phi0s6); + + + dlam = lambda - M0; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + + phis = sin(phi); + + if(phi==po2) + { + qq = qp; + qqo = (double)1.; + } + else + { + x = e * phis; + qq = om*(phis/((double)1.-e2*phis*phis)-oo* + log(((double)1.-x)/((double)1.+x))); + qqo = qq/qp; + } + + if(qqo>(double)1.) + qqo = (double)1.; + else if(qqo<(double)-1.) + qqo = (double)-1.; + + bt = asin(qqo); + btc = atan(tan(bt)/cos(dlam)); + + if((fabs(btc)-po2)>(double)1.0e-8) + PHIc = btc; + else + { + bts2 = A0 * sin((double)2.0*btc); + bts4 = A1 * sin((double)4.0*btc); + bts6 = A2 * sin((double)6.0*btc); + PHIc = btc + bts2 + bts4 + bts6; + } + + PHIcs = sin(PHIc); + *E = a*cos(bt)*cos(PHIc)*sin(dlam)/(sf*cos(btc)* + pow((double)1.-e2*PHIcs*PHIcs, + (double).5)) + E0; + PHI = c0 * PHIc; + PHIs2 = c1 * sin((double)2.0*PHIc); + PHIs4 = c2 * sin((double)4.0*PHIc); + PHIs6 = c3 * sin((double)6.0*PHIc); + Mc = a*(PHI-PHIs2+PHIs4-PHIs6); + + *N = sf * (Mc-AM0) + N0; + + return; +} + + + + +/* @func GPS_Math_TCylEA_EN_To_LatLon ********************************** +** +** Convert transverse cylindrical equal area easting and northing projection +** to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] M0 [double] central meridian (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_TCylEA_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e; + double e2; + double e4; + double e6; + double AM0; + double qp; + double om; + double oo; + double c0; + double c1; + double c2; + double c3; + double b0; + double b1; + double B2; + double b3; + double A0; + double A1; + double A2; + double sf; + double x; + double som; + double phis; + double j; + double te4; + double lat; + double phi0s2; + double phi0s4; + double phi0s6; + double E1; + double E2; + double E3; + double E4; + + double dx; + double dy; + double bt; + double btc; + double btp; + double btcc; + double Mc; + double Muc; + double mus2; + double mus4; + double mus6; + double mus8; + double bts2; + double bts4; + double bts6; + double PHIc; + double Qc; + double Qco; + double t; + + + sf = (double)1.0; /* scale factor */ + + phi0 = GPS_Math_Deg_To_Rad(phi0); + M0 = GPS_Math_Deg_To_Rad(M0); + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(M0>GPS_PI) + M0 -= p2; + a2 = a*a; + b2 = b*b; + e2 = (a2-b2)/a2; + e4 = e2*e2; + e6 = e2*e4; + e = pow(e2,(double).5); + om = (double)1.-e2; + som = pow(om,(double).5); + oo = (double)1./((double)2.*e); + + phis = sin(po2); + x = e * phis; + qp = om*(phis/((double)1.-e2*phis*phis)-oo* + log(((double)1.-x)/((double)1.+x))); + + A0 = e2 / (double)3.+(double)31.*e4/(double)180.+(double)517.* + e6/(double)5040.; + A1 = (double)23.*e4/(double)360.+(double)251.*e6/(double)3780.; + A2 = (double)761.*e6/(double)45360.; + + E1 = ((double)1.0-som) / ((double)1.0+som); + E2 = E1*E1; + E3 = E2*E1; + E4 = E3*E1; + + b0 = (double)3.*E1/(double)2.-(double)27.*E3/(double)32.; + b1 = (double)21.*E2/(double)16.-(double)55.*E4/(double)32.; + B2 = (double)151.*E3/(double)96.; + b3 = (double)1097.*E4/(double)512.; + + + j = (double)45.0*e6/(double)1024.0; + te4 = (double)3.0 * e4; + c0 = (double)1.0-e2/(double)4.0-te4/(double)64.0-(double)5.0*e6/ + (double)256.0; + c1 = (double)3.0*e2/(double)8.0+te4/(double)32.0+j; + c2 = (double)15.0*e4/(double)256.0+j; + c3 = (double)35.0*e6/(double)3072.0; + + lat = c0 * phi0; + + phi0s2 = c1 * sin((double)2.0*phi0); + phi0s4 = c2 * sin((double)4.0*phi0); + phi0s6 = c3 * sin((double)6.0*phi0); + AM0 = a*(lat-phi0s2+phi0s4-phi0s6); + + + + dx = E - E0; + dy = N - N0; + Mc = AM0 + dy/sf; + Muc = Mc / (c0*a); + + mus2 = b0 * sin((double)2.0*Muc); + mus4 = b1 * sin((double)4.0*Muc); + mus6 = B2 * sin((double)6.0*Muc); + mus8 = b3 * sin((double)6.0*Muc); + PHIc = Muc + mus2 + mus4 + mus6 + mus8; + + phis = sin(PHIc); + x = e * phis; + Qc = om*(phis/((double)1.-e2*phis*phis)-oo* + log(((double)1.-x)/((double)1.+x))); + Qco = Qc/qp; + + if(Qco>(double)1.) + Qco = (double)1.; + else if(Qco<(double)-1.) + Qco = (double)-1.; + + btc = asin(Qco); + btcc = cos(btc); + t = sf*dx*btcc*pow((double)1.-e2*phis*phis,(double).5)/(a*cos(PHIc)); + if(t>(double)1.) + t=(double)1.; + else if(t<(double)-1.) + t=(double)-1.; + btp = -asin(t); + bt = asin(cos(btp)*sin(btc)); + + bts2 = A0 * sin((double)2.0*bt); + bts4 = A1 * sin((double)4.0*bt); + bts6 = A2 * sin((double)6.0*bt); + *phi = bt + bts2 + bts4 + bts6; + *lambda = M0 - atan(tan(btp)/btcc); + + if(*phi>po2) + *phi = po2; + else if(*phi<-po2) + *phi = -po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda = GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_Mercator_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to standard Mercator projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] lambda0 [double] longitude of origin (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Mercator_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double lambda0, + double E0, double N0, double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e3; + double e; + double es; + double ab; + double bb; + double cb; + double db; + double ml; + double phi0s; + double sf; + + double dlam; + double ct; + double ex; + double tt; + double pt; + + + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + phi0 = GPS_Math_Deg_To_Rad(phi0); + lambda0 = GPS_Math_Deg_To_Rad(lambda0); + + ml = ((double)GPS_PI*(double)89.5)/(double)180.; + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(lambda0>GPS_PI) + lambda0 -= p2; + a2 = a*a; + b2 = b*b; + es = (a2-b2)/a2; + e2 = es*es; + e3 = e2*es; + e4 = e3*es; + + e = pow(es,(double).5); + phi0s = sin(phi0); + sf = (double)1. / (pow((double)1.-es*phi0s*phi0s,(double).5)/cos(phi0)); + + ab = es/(double)2.+(double)5.*e2/(double)24.+e3/(double)12.+(double)13.* + e4/(double)360.; + bb = (double)7.*e2/(double)48.+(double)29.*e3/(double)240.+ + (double)811.*e4/(double)11520.; + cb = (double)7.*e3/(double)120.+(double)81.*e4/(double)1120.; + db = (double)4279.*e4/(double)161280.; + + + + if(lambda>(double)GPS_PI) + lambda -= p2; + + dlam = lambda - lambda0; + if(dlam>GPS_PI) + dlam -= p2; + if(dlam<-GPS_PI) + dlam += p2; + + + ex = e * sin(phi); + tt = tan((double)GPS_PI/(double)4.+phi/(double)2.); + pt = pow((((double)1.-ex)/((double)1.+ex)),(e/(double)2.)); + + ct = tt * pt; + *N = sf * a * log(ct) + N0; + *E = sf * a * dlam + E0; + + return; +} + + + + +/* @func GPS_Math_Mercator_EN_To_LatLon ********************************** +** +** Convert standard Mercator easting and northing projection +** to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] lambda0 [double] longitude of origin (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_Mercator_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, + double lambda0, double E0, double N0, + double a, double b) +{ + double p2; + double po2; + double a2; + double b2; + double e2; + double e4; + double e3; + double e; + double es; + double ab; + double bb; + double cb; + double db; + double ml; + double phi0s; + double sf; + + double dx; + double dy; + double x; + + phi0 = GPS_Math_Deg_To_Rad(phi0); + lambda0 = GPS_Math_Deg_To_Rad(lambda0); + + ml = ((double)GPS_PI*(double)89.5)/(double)180.; + + p2 = (double)GPS_PI * (double)2.0; + po2 = (double)GPS_PI / (double)2.0; + if(lambda0>GPS_PI) + lambda0 -= p2; + a2 = a*a; + b2 = b*b; + es = (a2-b2)/a2; + e2 = es*es; + e3 = e2*es; + e4 = e3*es; + + e = pow(es,(double).5); + phi0s = sin(phi0); + sf = (double)1. / (pow((double)1.-es*phi0s*phi0s,(double).5)/cos(phi0)); + + ab = es/(double)2.+(double)5.*e2/(double)24.+e3/(double)12.+(double)13.* + e4/(double)360.; + bb = (double)7.*e2/(double)48.+(double)29.*e3/(double)240.+ + (double)811.*e4/(double)11520.; + cb = (double)7.*e3/(double)120.+(double)81.*e4/(double)1120.; + db = (double)4279.*e4/(double)161280.; + + dx = E - E0; + dy = N - N0; + *lambda = lambda0 + dx / (sf*a); + x = (double)GPS_PI / (double)2. - + (double)2.*atan((double)1./exp(dy/(sf*a))); + *phi = x+ab*sin((double)2.*x)+bb*sin((double)4.*x)+cb*sin((double)6.*x) + + db*sin((double)8.*x); + + if(*phi>po2) + *phi = po2; + else if(*phi<-po2) + *phi = -po2; + + if(*lambda>GPS_PI) + *lambda -= p2; + if(*lambda<-GPS_PI) + *lambda += p2; + + if(*lambda>GPS_PI) + *lambda = GPS_PI; + else if(*lambda<-GPS_PI) + *lambda=-GPS_PI; + + *lambda = GPS_Math_Rad_To_Deg(*lambda); + *phi = GPS_Math_Rad_To_Deg(*phi); + + return; +} + + + + +/* @func GPS_Math_TMerc_LatLon_To_EN ********************************** +** +** Convert latitude and longitude to transverse Mercator projection +** easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] lambda0 [double] longitude of origin (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] F0 [double] scale factor +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_TMerc_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double lambda0, + double E0, double N0, double F0, + double a, double b) +{ + GPS_Math_LatLon_To_EN(E,N,phi,lambda,N0,E0,phi0,lambda0,F0,a,b); + + return; +} + + + + +/* @func GPS_Math_TMerc_EN_To_LatLon ********************************** +** +** Convert transverse Mercator easting and northing projection +** to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi0 [double] latitude of origin (deg) +** @param [r] lambda0 [double] longitude of origin (deg) +** @param [r] E0 [double] false easting +** @param [r] N0 [double] false northing +** @param [r] F0 [double] scale factor +** @param [r] a [double] semi-major axis +** @param [r] b [double] semi-minor axis +** +** @return [void] +************************************************************************/ +void GPS_Math_TMerc_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double lambda0, + double E0, double N0, double F0, + double a, double b) +{ + GPS_Math_EN_To_LatLon(E,N,phi,lambda,N0,E0,phi0,lambda0,F0,a,b); + + return; +} + + + + +/* @func GPS_Math_Swiss_LatLon_To_EN *********************************** +** +** Convert latitude and longitude to Swiss grid easting and northing +** +** @param [r] phi [double] latitude (deg) +** @param [r] lambda [double] longitude (deg) +** @param [w] E [double *] easting (metre) +** @param [w] N [double *] northing (metre) +** @param [r] phi0 [double] latitude origin (deg) [normally 46.95240556] +** @param [r] lambda0 [double] longitude origin (deg) [normally 7.43958333] +** @param [r] E0 [double] false easting (metre) [normally 600000.0] +** @param [r] N0 [double] false northing (metre) [normally 200000.0] +** @param [r] a [double] semi-major axis [normally 6377397.000] +** @param [r] b [double] semi-minor axis [normally 6356078.823] +** +** @return [void] +***************************************************************************/ +void GPS_Math_Swiss_LatLon_To_EN(double phi, double lambda, double *E, + double *N,double phi0,double lambda0, + double E0, double N0, double a, double b) + +{ + double a2; + double b2; + double esq; + double e; + double c; + double ephi0p; + double phip; + double sphip; + double phid; + double slambda2; + double lambda1; + double lambda2; + double K; + double po4; + double w; + double R; + + lambda0 = GPS_Math_Deg_To_Rad(lambda0); + phi0 = GPS_Math_Deg_To_Rad(phi0); + lambda = GPS_Math_Deg_To_Rad(lambda); + phi = GPS_Math_Deg_To_Rad(phi); + + po4=GPS_PI/(double)4.0; + + a2 = a*a; + b2 = b*b; + esq = (a2-b2)/a2; + e = pow(esq,(double)0.5); + + c = sqrt(1+((esq*pow(cos(phi0),(double)4.))/((double)1.-esq))); + + ephi0p = asin(sin(phi0)/c); + + K = log(tan(po4+ephi0p/(double)2.)) - c*(log(tan(po4+phi0/(double)2.)) - + e/(double)2. * log(((double)1.+e*sin(phi0)) / + ((double)1.-e*sin(phi0)))); + lambda1 = c*(lambda-lambda0); + w = c*(log(tan(po4+phi/(double)2.)) - e/(double)2. * + log(((double)1.+e*sin(phi)) / ((double)1.-e*sin(phi)))) + K; + + + phip = (double)2. * (atan(exp(w)) - po4); + + sphip = cos(ephi0p) * sin(phip) - sin(ephi0p) * cos(phip) * cos(lambda1); + phid = asin(sphip); + + slambda2 = cos(phip)*sin(lambda1) / cos(phid); + lambda2 = asin(slambda2); + + R = a*sqrt((double)1.-esq) / ((double)1.-esq*sin(phi0) * sin(phi0)); + + *N = R*log(tan(po4 + phid/(double)2.)) + N0; + *E = R*lambda2 + E0; + return; +} + + + + +/* @func GPS_Math_Swiss_EN_To_LatLon ************************************ +** +** Convert Swiss Grid easting and northing to latitude and longitude +** +** @param [r] E [double] easting (metre) +** @param [r] N [double] northing (metre) +** @param [w] phi [double *] latitude (deg) +** @param [w] lambda [double *] longitude (deg) +** @param [r] phi0 [double] latitude origin (deg) [normally 46.95240556] +** @param [r] lambda0 [double] longitude origin (deg) [normally 7.43958333] +** @param [r] E0 [double] false easting (metre) [normally 600000.0] +** @param [r] N0 [double] false northing (metre) [normally 200000.0] +** @param [r] a [double] semi-major axis [normally 6377397.000] +** @param [r] b [double] semi-minor axis [normally 6356078.823] +** +** @return [void] +*************************************************************************/ + +void GPS_Math_Swiss_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double lambda0, + double E0, double N0, double a, double b) +{ + double a2; + double b2; + double esq; + double e; + double R; + double c; + double po4; + double phid; + double phi1; + double lambdad; + double lambda1; + double slambda1; + double ephi0p; + double sphip; + double tol; + double cr; + double C; + double K; + + lambda0 = GPS_Math_Deg_To_Rad(lambda0); + phi0 = GPS_Math_Deg_To_Rad(phi0); + + po4=GPS_PI/(double)4.0; + tol=(double)0.00001; + + a2 = a*a; + b2 = b*b; + esq = (a2-b2)/a2; + e = pow(esq,(double)0.5); + + R = a*sqrt((double)1.-esq) / ((double)1.-esq*sin(phi0) * sin(phi0)); + + phid = (double)2.*(atan(exp((N - N0)/R)) - po4); + lambdad = (E - E0)/R; + + c = sqrt((double)1.+((esq * pow(cos(phi0), (double)4.)) / + ((double)1.-esq))); + ephi0p = asin(sin(phi0) / c); + + sphip = cos(ephi0p)*sin(phid) + sin(ephi0p)*cos(phid)*cos(lambdad); + phi1 = asin(sphip); + + slambda1 = cos(phid)*sin(lambdad)/cos(phi1); + lambda1 = asin(slambda1); + + *lambda = GPS_Math_Rad_To_Deg((lambda1/c + lambda0)); + + K = log(tan(po4 + ephi0p/(double)2.)) -c*(log(tan(po4 + phi0/(double)2.)) + - e/(double)2. * log(((double)1.+e*sin(phi0)) / + ((double)1.-e*sin(phi0)))); + C = (K - log(tan(po4 + phi1/(double)2.)))/c; + + do + { + cr = (C + log(tan(po4 + phi1/(double)2.)) - e/(double)2. * + log(((double)1.+e*sin(phi1)) / ((double)1.-e*sin(phi1)))) * + ((((double)1.-esq*sin(phi1)*sin(phi1)) * cos(phi1)) / + ((double)1.-esq)); + phi1 -= cr; + } + while (fabs(cr) > tol); + + *phi = GPS_Math_Rad_To_Deg(phi1); + + return; +} diff --git a/jeeps/gpsproj.h b/jeeps/gpsproj.h new file mode 100644 index 000000000..6922a47e0 --- /dev/null +++ b/jeeps/gpsproj.h @@ -0,0 +1,157 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsproj_h +#define gpsproj_h + + +#include "gps.h" + +void GPS_Math_Albers_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi1, double phi2, + double phi0, double M0, double E0, + double N0, double a, double b); +void GPS_Math_Albers_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi1, double phi2, + double phi0, double M0, double E0, + double N0, double a, double b); + + +void GPS_Math_LambertCC_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi1, double phi2, + double phi0, double M0, double E0, + double N0, double a, double b); +void GPS_Math_LambertCC_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi1, double phi2, + double phi0, double M0, double E0, + double N0, double a, double b); + +void GPS_Math_Miller_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, + double N0, double a, double b); +void GPS_Math_Miller_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b); + +void GPS_Math_Bonne_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, double E0, + double N0, double a, double b); +void GPS_Math_Bonne_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b); + +void GPS_Math_Cassini_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, + double E0, double N0, double a, double b); +void GPS_Math_Cassini_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b); + +void GPS_Math_Cylea_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, + double E0, double N0, double a, double b); +void GPS_Math_Cylea_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b); + +void GPS_Math_EckertIV_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, double N0, + double a, double b); +void GPS_Math_EckertIV_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b); + +void GPS_Math_EckertVI_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, double N0, + double a, double b); +void GPS_Math_EckertVI_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b); + +void GPS_Math_Cyled_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, double E0, + double N0, double a, double b); +void GPS_Math_Cyled_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b); + +void GPS_Math_VderGrinten_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, + double N0, double a, double b); +void GPS_Math_VderGrinten_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b); + +void GPS_Math_PolarSt_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi1, double lambda1, + double E0, double N0, double a, double b); +void GPS_Math_PolarSt_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi1, double lambda1, + double E0, double N0, double a, double b); + +void GPS_Math_Mollweide_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, + double N0, double a, double b); +void GPS_Math_Mollweide_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b); + +void GPS_Math_Orthog_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double lambda0, + double E0, double N0, double a, double b); +void GPS_Math_Orthog_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double lambda0, + double E0, double N0, double a, double b); + +void GPS_Math_Polycon_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, + double E0, double N0, double a, double b); +void GPS_Math_Polycon_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b); + +void GPS_Math_Sinusoid_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double M0, double E0, + double N0, double a, double b); +void GPS_Math_Sinusoid_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double M0, double E0, + double N0, double a, double b); + +void GPS_Math_TCylEA_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double M0, double E0, + double N0, double a, double b); +void GPS_Math_TCylEA_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double M0, + double E0, double N0, double a, double b); + +void GPS_Math_Mercator_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double lambda0, + double E0, double N0, double a, double b); +void GPS_Math_Mercator_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, + double lambda0, double E0, double N0, + double a, double b); + +void GPS_Math_TMerc_LatLon_To_EN(double phi, double lambda, double *E, + double *N, double phi0, double lambda0, + double E0, double N0, double F0, + double a, double b); +void GPS_Math_TMerc_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double lambda0, + double E0, double N0, double F0, + double a, double b); + +void GPS_Math_Swiss_LatLon_To_EN(double phi, double lambda, double *E, + double *N,double phi0,double lambda0, + double E0, double N0, double a, double b); +void GPS_Math_Swiss_EN_To_LatLon(double E, double N, double *phi, + double *lambda, double phi0, double lambda0, + double E0, double N0, double a, double b); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsprot.c b/jeeps/gpsprot.c new file mode 100644 index 000000000..50606b7d2 --- /dev/null +++ b/jeeps/gpsprot.c @@ -0,0 +1,366 @@ +/******************************************************************** +** @source JEEPS protocol table lookup functions (GPS' without A001) +** +** @author Copyright (C) 1999 Alan Bleasby +** @version 1.0 +** @modified Dec 28 1999 Alan Bleasby. First version +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include + +#define GPS_TAGUNK 20 + +/* Storage for any unknown tags */ +static int32 gps_tag_unknown[GPS_TAGUNK]; +static int32 gps_tag_data_unknown[GPS_TAGUNK]; +static int32 gps_n_tag_unknown = 0; + + + +struct COMMANDDATA COMMAND_ID[2]= +{ + { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x31,0x32 + } + , + { + 0x00,0x04,0x00,0x00,0x08,0x14,0x00,0x15,0x1a,0x00,0x00 + } +}; + +struct LINKDATA LINK_ID[3]= +{ + { + 0x06,0,0,0,0,0,0x15,0,0,0,0,0,0,0,0,0,0xfd,0xfe,0xff + } + , + { + 0x06,0x0a,0x0c,0x0e,0x11,0x13,0x15,0x1b,0x1d,0x1e, + 0x1f,0x22,0x23,0x33,0x62,0x63,0xfd,0xfe,0xff + } + , + { + 0x06,0x0b,0x0c,0x14,0x18,0,0x15,0x23,0x25,0x27,0x04, + 0,0x2b,0,0,0,0xfd,0xfe,0xff + } +}; + +struct GPS_MODEL_PROTOCOL GPS_MP[]= +{ + { 7,pL001,pA010,pA100,pD100,pA200,pD200,-1,-1,-1,-1, + pA500,pD500 + }, + { 13,pL001,pA010,pA100,pD100,pA200,pD200,pD100,pA300,pD300,pA400,pD400, + pA500,pD500 + }, + { 14,pL001,pA010,pA100,pD100,pA200,pD200,pD100,-1,-1,pA400,pD400, + pA500,pD500 + }, + { 15,pL001,pA010,pA100,pD151,pA200,pD200,pD151,-1,-1,pA400,pD151, + pA500,pD500 + }, + { 18,pL001,pA010,pA100,pD100,pA200,pD200,pD100,pA300,pD300,pA400,pD400, + pA500,pD500 + }, + { 20,pL002,pA011,pA100,pD150,pA200,pD201,pD150,-1,-1,pA400,pD450, + pA500,pD550 + }, + { 22,pL001,pA010,pA100,pD152,pA200,pD200,pD152,pA300,pD300,pA400,pD152, + pA500,pD500 + }, + { 23,pL001,pA010,pA100,pD100,pA200,pD200,pD100,pA300,pD300,pA400,pD400, + pA500,pD500 + }, + { 24,pL001,pA010,pA100,pD100,pA200,pD200,pD100,pA300,pD300,pA400,pD400, + pA500,pD500 + }, + { 25,pL001,pA010,pA100,pD100,pA200,pD200,pD100,pA300,pD300,pA400,pD400, + pA500,pD500 + }, + { 29,pL001,pA010,pA100,pD101,pA200,pD201,pD101,pA300,pD300,pA400,pD101, + pA500,pD500 + }, + { 929,pL001,pA010,pA100,pD102,pA200,pD201,pD102,pA300,pD300,pA400,pD102, + pA500,pD500 + }, + { 31,pL001,pA010,pA100,pD100,pA200,pD201,pD100,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 33,pL002,pA011,pA100,pD150,pA200,pD201,pD150,-1,-1,pA400,pD450, + pA500,pD550 + }, + { 34,pL002,pA011,pA100,pD150,pA200,pD201,pD150,-1,-1,pA400,pD450, + pA500,pD550 + }, + { 35,pL001,pA010,pA100,pD100,pA200,pD200,pD100,pA300,pD300,pA400,pD400, + pA500,pD500 + }, + { 36,pL001,pA010,pA100,pD152,pA200,pD200,pD152,pA300,pD300,pA400,pD152, + pA500,pD500 + }, + { 936,pL001,pA010,pA100,pD152,pA200,pD200,pD152,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 39,pL001,pA010,pA100,pD151,pA200,pD201,pD151,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 41,pL001,pA010,pA100,pD100,pA200,pD201,pD100,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 42,pL001,pA010,pA100,pD100,pA200,pD200,pD100,pA300,pD300,pA400,pD400, + pA500,pD500 + }, + { 44,pL001,pA010,pA100,pD101,pA200,pD201,pD101,pA300,pD300,pA400,pD101, + pA500,pD500 + }, + { 45,pL001,pA010,pA100,pD152,pA200,pD201,pD152,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 47,pL001,pA010,pA100,pD100,pA200,pD201,pD100,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 48,pL001,pA010,pA100,pD154,pA200,pD201,pD154,pA300,pD300,-1,-1, + pA500,pD501 + }, + { 49,pL001,pA010,pA100,pD102,pA200,pD201,pD102,pA300,pD300,pA400,pD102, + pA500,pD501 + }, + { 50,pL001,pA010,pA100,pD152,pA200,pD201,pD152,pA300,pD300,-1,-1, + pA500,pD501 + }, + { 52,pL002,pA011,pA100,pD150,pA200,pD201,pD150,-1,-1,pA400,pD450, + pA500,pD550 + }, + { 53,pL001,pA010,pA100,pD152,pA200,pD201,pD152,pA300,pD300,-1,-1, + pA500,pD501 + }, + { 55,pL001,pA010,pA100,pD100,pA200,pD201,pD100,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 56,pL001,pA010,pA100,pD100,pA200,pD201,pD100,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 59,pL001,pA010,pA100,pD100,pA200,pD201,pD100,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 61,pL001,pA010,pA100,pD100,pA200,pD201,pD100,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 62,pL001,pA010,pA100,pD100,pA200,pD201,pD100,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 64,pL002,pA011,pA100,pD150,pA200,pD201,pD150,-1,-1,pA400,pD450, + pA500,pD551 + }, + { 71,pL001,pA010,pA100,pD155,pA200,pD201,pD155,pA300,pD300,-1,-1, + pA500,pD501 + }, + { 72,pL001,pA010,pA100,pD104,pA200,pD201,pD104,pA300,pD300,-1,-1, + pA500,pD501 + }, + { 73,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,-1,-1, + pA500,pD501 + }, + { 74,pL001,pA010,pA100,pD100,pA200,pD201,pD100,pA300,pD300,-1,-1, + pA500,pD500 + }, + { 76,pL001,pA010,pA100,pD102,pA200,pD201,pD102,pA300,pD300,pA400,pD102, + pA500,pD501 + }, + { 77,pL001,pA010,pA100,pD100,pA200,pD201,pD100,pA300,pD300,pA400,pD400, + pA500,pD501 + }, + { 777,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,pA400,pD403, + pA500,pD501 + }, + { 877,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,-1,-1, + pA500,pD501 + }, + { 977,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,pA400,pD403, + pA500,pD501 + }, + { 87,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,pA400,pD403, + pA500,pD501 + }, + { 88,pL001,pA010,pA100,pD102,pA200,pD201,pD102,pA300,pD300,pA400,pD102, + pA500,pD501 + }, + { 95,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,pA400,pD403, + pA500,pD501 + }, + { 96,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,pA400,pD403, + pA500,pD501 + }, + { 97,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,-1,-1, + pA500,pD501 + }, + { 98,pL002,pA011,pA100,pD150,pA200,pD201,pD150,-1,-1,pA400,pD450, + pA500,pD551 + }, + { 100,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,pA400,pD403, + pA500,pD501 + }, + { 105,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,pA400,pD403, + pA500,pD501 + }, + { 106,pL001,pA010,pA100,pD103,pA200,pD201,pD103,pA300,pD300,pA400,pD403, + pA500,pD501 + }, + { 112,pL001,pA010,pA100,pD152,pA200,pD201,pD152,pA300,pD300,-1,-1, + pA500,pD501 + }, + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0 + } +}; + + +/* @func GPS_Protocol_Version_Change ************************************ +** +** Alters/recalculates ID, if necessary, for indexing the GPS_MP +** structure in order to find available protocols. +** +** @param [r] id [US] Garmin id +** @param [r] version [UD] Garmin version +** +** @return [void] +************************************************************************/ + +US GPS_Protocol_Version_Change(US id, US version) +{ + if(id==29) + if(version>=400) + id = 929; + + if(id==36) + if(version>=300) + id = 936; + + if(id==77) + { + if(version>=301 && version<350) + id = 777; + else if(version>=350 && version<361) + id = 877; + else if(version>=361) + id = 977; + } + + return id; +} + + + +/* @func GPS_Protocol_Table_Set ************************************ +** +** Set protocol capabilities based on table look-up +** For those units without the A001 protocol +** +** @param [r] id [const US] id +** +** @return [int32] Success +************************************************************************/ + +int32 GPS_Protocol_Table_Set(US id) +{ + int32 i; + US v; + char s[GPS_ARB_LEN]; + + i=0; + while((v=GPS_MP[i].id)) + { + if(v==id) + { + gps_link_type = GPS_MP[i].link; + gps_device_command = GPS_MP[i].command-10; + gps_waypt_transfer = GPS_MP[i].wayptt; + gps_waypt_type = GPS_MP[i].wayptd; + gps_route_transfer = GPS_MP[i].rtea; + gps_rte_hdr_type = GPS_MP[i].rted0; + gps_rte_type = GPS_MP[i].rted1; + gps_trk_transfer = GPS_MP[i].trka; + gps_trk_type = GPS_MP[i].trkd; + gps_prx_waypt_transfer = GPS_MP[i].prxa; + gps_prx_waypt_type = GPS_MP[i].prxd; + gps_almanac_transfer = GPS_MP[i].alma; + gps_almanac_type = GPS_MP[i].almd; + return 1; + } + ++i; + } + + + (void)sprintf(s,"INIT: No table entry for ID %d\n",id); + GPS_Error(s); + + return GPS_UNSUPPORTED; +} + + +/* @func GPS_Protocol_Error ******************************************* +** +** Called if an unrecognised/illegal protocol is met +** For those units with the A001 protocol +** +** @param [r] tag [const US] tag +** @param [r] data [const US] data +** +** @return [void] +************************************************************************/ + +void GPS_Protocol_Error(US tag, US data) +{ + char s[GPS_ARB_LEN]; + + (void) sprintf(s,"PROTOCOL ERROR: Unknown tag/data [%c/%d]\n",tag,data); + GPS_Error(s); + + if(gps_n_tag_unknown < GPS_TAGUNK) + { + gps_tag_unknown[gps_n_tag_unknown] = tag; + gps_tag_data_unknown[gps_n_tag_unknown++] = data; + } + + return; +} + + + +/* @func GPS_Unknown_Protocol_Print ******************************************* +** +** Diagnostic routine for printing out any unknown protocols +** For those units with the A001 protocol +** +** @return [void] +************************************************************************/ + +void GPS_Unknown_Protocol_Print(void) +{ + int32 i; + + (void) fprintf(stdout,"\nUnknown protocols: "); + if(!gps_n_tag_unknown) + (void) fprintf(stdout,"None"); + (void) fprintf(stdout,"\n"); + + for(i=0; i +#include +#include +#include + + +/* @func GPS_Time_Now *********************************************** +** +** Get current time +** +** @return [time_t] number of bytes read +**********************************************************************/ + +time_t GPS_Time_Now(void) +{ + time_t secs; + + if(time(&secs)==-1) + { + perror("time"); + GPS_Error("GPS_Time_Now: Error reading time"); + gps_errno = HARDWARE_ERROR; + return 0; + } + + return secs; +} + + + + + + + +/* @func GPS_Packet_Read *********************************************** +** +** Read a packet +** +** @param [r] fd [int32] file descriptor +** @param [w] packet [GPS_PPacket *] packet string +** +** @return [int32] number of bytes read +**********************************************************************/ + +int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet) +{ + time_t start; + int32 n; + int32 len; + UC u; + int32 isDLE; + UC *p; + int32 i; + UC chk=0; + const char *m1; + const char *m2; + + len = 0; + isDLE = gpsFalse; + p = (*packet)->data; + + if (gps_is_usb) { + return GPS_Packet_Read_usb(fd, packet); + } + + start = GPS_Time_Now(); + GPS_Diag("Rx Data:"); + while(GPS_Time_Now() < start+GPS_TIME_OUT) + { + if((n=GPS_Serial_Chars_Ready(fd))) + { + if(GPS_Serial_Read(fd,&u,1)==-1) + { + perror("read"); + GPS_Error("GPS_Packet_Read: Read error"); + gps_errno = FRAMING_ERROR; + return 0; + } + + GPS_Diag("%02x ", u); + + if(!len) + { + (*packet)->dle = u; + if(u != DLE) + { + (void) fprintf(stderr,"GPS_Packet_Read: No DLE\n"); + (void) fflush(stderr); + return 0; + } + ++len; + continue; + } + + if(len==1) + { + (*packet)->type = u; + ++len; + continue; + } + + if(u == DLE) + { + if(isDLE) + { + isDLE = gpsFalse; + continue; + } + isDLE = gpsTrue; + } + + if(len == 2) + { + (*packet)->n = u; + len = -1; + continue; + } + + if(u == ETX) + if(isDLE) + { + (*packet)->edle = DLE; + (*packet)->etx = ETX; + if(p-(*packet)->data-2 != (*packet)->n) + { + GPS_Error("GPS_Packet_Read: Bad count"); + gps_errno = FRAMING_ERROR; + return 0; + } + (*packet)->chk = *(p-2); + + for(i=0,p=(*packet)->data;i<(*packet)->n;++i) + chk -= *p++; + chk -= (*packet)->type; + chk -= (*packet)->n; + if(chk != (*packet)->chk) + { + GPS_Error("CHECKSUM: Read error\n"); + gps_errno = FRAMING_ERROR; + return 0; + } + + m1 = Get_Pkt_Type((*packet)->type, (*packet)->data[0], &m2); + GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); + return (*packet)->n; + } + + *p++ = u; + } + } + + + GPS_Error("GPS_Packet_Read: Time-out"); + gps_errno = SERIAL_ERROR; + + return 0; +} + + + +/* @func GPS_Get_Ack ************************************************* +** +** Check that returned packet is an ack for the packet sent +** +** @param [r] fd [int32] file descriptor +** @param [r] tra [GPS_PPacket *] packet just transmitted +** @param [r] rec [GPS_PPacket *] packet to receive +** +** @return [int32] true if ACK +**********************************************************************/ + +int32 GPS_Get_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec) +{ + if (gps_is_usb) { + return 1; + } + + if(!GPS_Packet_Read(fd, rec)) + return 0; + + if(LINK_ID[0].Pid_Ack_Byte != (*rec)->type) + { + gps_error = FRAMING_ERROR; +/* rjl return 0; */ + } + + if(*(*rec)->data != (*tra)->type) + { + gps_error = FRAMING_ERROR; + return 0; + } + + return 1; +} diff --git a/jeeps/gpsread.h b/jeeps/gpsread.h new file mode 100644 index 000000000..138cc5866 --- /dev/null +++ b/jeeps/gpsread.h @@ -0,0 +1,23 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsread_h +#define gpsread_h + + +#include "gps.h" +#include + +time_t GPS_Time_Now(void); +int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet); +int32 GPS_Get_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec); +int32 ajb(int32 fd); + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsrqst.c b/jeeps/gpsrqst.c new file mode 100644 index 000000000..827559071 --- /dev/null +++ b/jeeps/gpsrqst.c @@ -0,0 +1,175 @@ +/******************************************************************** +** @source JEEPS time/position request from GPS functions +** +** @author Copyright (C) 1999 Alan Bleasby +** @version 1.0 +** @modified Dec 28 1999 Alan Bleasby. First version +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" + + +static int32 GPS_A600_Rqst(int32 fd, time_t Time); +static int32 GPS_A700_Rqst(int32 fd, double lat, double lon); + + + +/* @func GPS_Rqst_Send_Time ****************************************** +** +** Set GPS time on request of GPS +** +** @param [r] fd [int32] file descriptor +** @param [r] Time [time_t] unix-style time +** +** @return [int32] true if OK +************************************************************************/ + +int32 GPS_Rqst_Send_Time(int32 fd, time_t Time) +{ + time_t ret=0; + + switch(gps_date_time_transfer) + { + case pA600: + ret = GPS_A600_Rqst(fd, Time); + break; + default: + GPS_Error("Rqst_Send_Time: Unknown date/time protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + +/* @funcstatic GPS_A600_Rqst ******************************************* +** +** Send time to GPS +** +** @param [r] fd [int32] file descriptor +** @param [r] Time [time_t] unix-style time +** +** @return [int32] success +************************************************************************/ +static int32 GPS_A600_Rqst(int32 fd, time_t Time) +{ + GPS_PPacket tra; + GPS_PPacket rec; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + switch(gps_date_time_type) + { + case pD600: + GPS_D600_Send(&tra,Time); + break; + default: + GPS_Error("A600_Rqst: Unknown data/time protocol"); + return PROTOCOL_ERROR; + } + + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_errno; + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + return 1; +} + + + +/* @func GPS_Rqst_Send_Position ****************************************** +** +** Set GPS position +** +** @param [r] fd [int32] filedescriptor +** @param [r] lat [double] latitude (deg) +** @param [r] lon [double] longitude (deg) +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Rqst_Send_Position(int32 fd, double lat, double lon) +{ + int32 ret=0; + + switch(gps_position_transfer) + { + case pA700: + ret = GPS_A700_Rqst(fd, lat, lon); + break; + default: + GPS_Error("Rqst_Send_Position: Unknown position protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + + + +/* @funcstatic GPS_A700_Rqst ******************************************* +** +** Send position to GPS +** +** @param [r] fd [int32] file descriptor +** @param [r] lat [double] latitude (deg) +** @param [r] lon [double] longitute (deg) +** +** @return [int32] success +************************************************************************/ +static int32 GPS_A700_Rqst(int32 fd, double lat, double lon) +{ + GPS_PPacket tra; + GPS_PPacket rec; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + + switch(gps_position_type) + { + case pD700: + GPS_D700_Send(&tra,lat,lon); + break; + default: + GPS_Error("A700_Rqst: Unknown position protocol"); + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + return PROTOCOL_ERROR; + } + + if(!GPS_Write_Packet(fd,tra)) + return gps_errno; + + if(!GPS_Get_Ack(fd, &tra, &rec)) + return gps_errno; + + + GPS_Packet_Del(&tra); + GPS_Packet_Del(&rec); + + return 1; +} + diff --git a/jeeps/gpsrqst.h b/jeeps/gpsrqst.h new file mode 100644 index 000000000..c6398ecd0 --- /dev/null +++ b/jeeps/gpsrqst.h @@ -0,0 +1,20 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsrqst_h +#define gpsrqst_h + + +#include "gps.h" + +int32 GPS_Rqst_Send_Time(int32 fd, time_t Time); +int32 GPS_Rqst_Send_Position(int32 fd, double lat, double lon); + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpssend.c b/jeeps/gpssend.c new file mode 100644 index 000000000..c4b299d7a --- /dev/null +++ b/jeeps/gpssend.c @@ -0,0 +1,219 @@ +/******************************************************************** +** @source JEEPS packet construction, sending and ack functions +** +** @author Copyright (C) 1999 Alan Bleasby +** @version 1.0 +** @modified Dec 28 1999 Alan Bleasby. First version +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include +#include + + +/* @func GPS_Make_Packet *********************************************** +** +** Forms a complete packet to send +** +** @param [w] packet [GPS_PPacket *] packet string +** @param [r] type [UC] packet type +** @param [r] data [UC *] data string +** @param [r] n [int16] number of bytes in data string +** +** @return [void] +************************************************************************/ + +void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n) +{ + UC *p; + UC *q; + + int32 i; + UC chk=0; + + + p = data; + q = (*packet)->data; + + if (gps_is_usb) { + GPS_Make_Packet_usb(packet, type, data, n); + return; + } + + (*packet)->dle = DLE; + (*packet)->edle = DLE; + (*packet)->etx = ETX; + (*packet)->n = n; + (*packet)->type = type; + (*packet)->bytes = 0; + + chk -= type; + + if(n == DLE) + { + ++(*packet)->bytes; + *q++ = DLE; + } + + + chk -= (UC) n; + + for(i=0;ibytes; + *q++ = DLE; + } + chk -= *p; + *q++ = *p++; + ++(*packet)->bytes; + } + + if(chk == DLE) + { + *q++ = DLE; + ++(*packet)->bytes; + } + + (*packet)->chk = chk; + + return; +} + + +void +Diag(void *buf, size_t sz) +{ + unsigned char *cbuf = (unsigned char *) buf; + while (sz--) { + GPS_Diag("%02x ", *cbuf++); + } +} + +void +DiagS(void *buf, size_t sz) +{ + unsigned char *cbuf = (unsigned char *) buf; + + while (sz--) { + unsigned char c = *cbuf++; + GPS_Diag("%c", isalnum(c) ? c : '.'); + } +} + +/* @func GPS_Write_Packet *********************************************** +** +** Forms a complete packet to send +** +** @param [w] fd [int32] file descriptor +** @param [r] packet [GPS_PPacket] packet +** +** @return [int32] number of bytes in the packet +************************************************************************/ + +int32 GPS_Write_Packet(int32 fd, GPS_PPacket packet) +{ + size_t ret; + const char *m1, *m2; + + if (gps_is_usb) + return GPS_Write_Packet_usb(fd, packet); + + GPS_Diag("Tx Data:"); + Diag(&packet->dle, 3); + if((ret=GPS_Serial_Write(fd,(const void *) &packet->dle,(size_t)3)) == -1) + { + perror("write"); + GPS_Error("SEND: Write to GPS failed"); + return 0; + } + if(ret!=3) + { + GPS_Error("SEND: Incomplete write to GPS"); + return 0; + } + + Diag(packet->data, packet->bytes); + if((ret=GPS_Serial_Write(fd,(const void *)packet->data,(size_t)packet->bytes)) == -1) + { + perror("write"); + GPS_Error("SEND: Write to GPS failed"); + return 0; + } + if(ret!=packet->bytes) + { + GPS_Error("SEND: Incomplete write to GPS"); + return 0; + } + + + Diag(&packet->chk, 3); + + GPS_Diag(": "); + DiagS(packet->data, packet->bytes); + DiagS(&packet->chk, 3); + m1 = Get_Pkt_Type(packet->type, packet->data[0], &m2); + GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); + + if((ret=GPS_Serial_Write(fd,(const void *)&packet->chk,(size_t)3)) == -1) + { + perror("write"); + GPS_Error("SEND: Write to GPS failed"); + return 0; + } + if(ret!=3) + { + GPS_Error("SEND: Incomplete write to GPS"); + return 0; + } + + + return 1; +} + + +/* @func GPS_Send_Ack *********************************************** +** +** Send an acknowledge packet +** +** @param [w] fd [int32] file descriptor +** @param [r] tra [GPS_PPacket *] packet to transmit +** @param [r] rec [GPS_PPacket *] last packet received +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Send_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec) +{ + UC data[2]; + + if (gps_is_usb) + return 1; + + GPS_Util_Put_Short(data,(US)(*rec)->type); + GPS_Make_Packet(tra,LINK_ID[0].Pid_Ack_Byte,data,2); + if(!GPS_Write_Packet(fd,*tra)) + { + GPS_Error("Error acknowledging packet"); + gps_errno = SERIAL_ERROR; + return 0; + } + + return 1; +} diff --git a/jeeps/gpssend.h b/jeeps/gpssend.h new file mode 100644 index 000000000..f048fdec8 --- /dev/null +++ b/jeeps/gpssend.h @@ -0,0 +1,26 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpssend_h +#define gpssend_h + + +#include "gps.h" + +#define GPS_ARB_LEN 1024 + +UC gps_sendbuf[GPS_ARB_LEN]; + +void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n); +int32 GPS_Write_Packet(int32 fd, GPS_PPacket packet); +int32 GPS_Send_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec); + + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsserial.c b/jeeps/gpsserial.c new file mode 100644 index 000000000..60b62545f --- /dev/null +++ b/jeeps/gpsserial.c @@ -0,0 +1,650 @@ +/******************************************************************** +** @source JEEPS serial port low level functions +** +** @author Copyright (C) 1999,2000 Alan Bleasby +** @version 1.0 +** @modified December 28th 1999 Alan Bleasby. First version +** @modified June 29th 2000 Alan Bleasby. NMEA additions +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include +#include +#include +#include +#include +#include + +#if 0 +#define GARMULATOR 1 +char *rxdata[] = { + "10 06 02 fe 00 fa 10 03", + "10 ff 7d 97 00 0e 01 53 74 72 65 65 74 50 69 6c 6f 74 20 33 20 53 6f 66 74 77 61 72 65 20 56 65 72 73 69 6f 6e 20 32 2e 37 30 00 56 45 52 42 4d 41 50 20 41 6d 65 72 69 63 61 73 20 41 75 74 6f 72 6f 75 74 65 20 31 2e 30 30 00 56 45 52 41 55 44 20 45 6e 67 6c 69 73 68 20 33 2e 30 31 00 56 45 52 53 50 4c 53 43 52 4e 20 53 70 6c 61 73 68 20 53 63 72 65 65 6e 20 4d 69 73 73 69 6e 67 00 f1 10 03", + "10 f8 0e 56 45 52 53 4d 41 50 31 20 4e 6f 6e 65 00 fb 10 03", + + /* Guessing from here down */ + /* "10 06 02 fe 00 fa 10 03", /* Ack the unknown packet */ + "10 fd 24 50 00 00 4c 01 00 41 0a 00 41 64 00 44 6d 00 41 c9 00 44 ca 00 44 6d 00 44 d2 00 41 2d 01 44 36 01 44 2d 01 66 10 03", /* PTR Array */ + "10 06 02 0a 00 ee 10 03", /* Ack */ + "10 0e 08 06 04 d4 07 00 17 3a 30 84 10 03", /* DATTIME */ + "10 06 02 0a 00 ee 10 03", /* Ack */ + "10 1b 02 09 00 da 10 03", /* RECORD */ + "10 06 02 0a 00 ee 10 03", /* Ack */ + "10 23 5f 01 00 ff 70 3f 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a6 1b aa 19 6e 78 5c c2 00 00 00 00 51 59 04 69 00 00 00 00 00 00 00 00 ff ff ff ff 47 43 31 41 33 37 00 54 68 65 20 54 72 6f 6c 6c 20 62 79 20 61 31 38 32 70 69 6c 6f 74 20 26 20 46 61 6d 69 6c 79 00 00 00 00 00 59 10 03" + "10 0c 02 07 00 eb 10 03" /* XFERCMP */ +}; +#endif +/* + * termio on Cygwin is apparently broken, so we revert to Windows serial. + */ +#if defined (__WIN32__) || defined (__CYGWIN__) + +#include +/* + * Rather than teaching the rest of this code about Windows serial APIs + * we'll weenie out, violate good layering, and just keep our handle + * internal. This means we ignore that 'fd' number that gets passed in. + */ + +void GPS_Serial_Error(char *hdr) +{ + char msg[200]; + char *s; + + strcpy(msg, hdr); + s = msg + strlen(hdr); + *s++ = ':'; + *s++ = ' '; + + FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, + GetLastError(), 0, s, sizeof(msg) - strlen(hdr) - 2, 0 ); + GPS_Error(msg); +} + +static HANDLE comport; + +int32 GPS_Serial_On(const char *port, int32 *fd) +{ + DCB tio; + COMMTIMEOUTS timeout; + + if (gps_is_usb) { + switch (gusb_open(port)) { + case 0: return 0; + case 1: return 1; + case 2: exit(0); + } + } + + comport = CreateFile(port, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, NULL); + + if (comport == INVALID_HANDLE_VALUE) { + GPS_Serial_Error("CreateFile"); + gps_errno = SERIAL_ERROR; + return 0; + } + + tio.DCBlength = sizeof(DCB); + GetCommState (comport, &tio); + tio.BaudRate = CBR_9600; + tio.fBinary = TRUE; + tio.fParity = TRUE; + tio.fOutxCtsFlow = FALSE; + tio.fOutxDsrFlow = FALSE; + tio.fDtrControl = DTR_CONTROL_ENABLE; + tio.fDsrSensitivity = FALSE; + tio.fTXContinueOnXoff = TRUE; + tio.fOutX = FALSE; + tio.fInX = FALSE; + tio.fErrorChar = FALSE; + tio.fNull = FALSE; + tio.fRtsControl = RTS_CONTROL_ENABLE; + tio.fAbortOnError = FALSE; + tio.ByteSize = 8; + tio.Parity = NOPARITY; + tio.StopBits = ONESTOPBIT; + + if (!SetCommState (comport, &tio)) { + GPS_Serial_Error("SetCommState"); + CloseHandle(comport); + comport = INVALID_HANDLE_VALUE; + gps_errno = SERIAL_ERROR; + return 0; + } + + /* + * The timeouts are kind of fictional as we always end up doing + * single byte reads. At 9600bps (the default) the individual + * character time is 104Millisecs, so these are mostly "dead-man" + * (i.e. cable unplugged, unit not turned on) values. + */ + GetCommTimeouts (comport, &timeout); + timeout.ReadIntervalTimeout = 1000; /*like vtime. In MS. */ + timeout.ReadTotalTimeoutMultiplier = 1000; + timeout.ReadTotalTimeoutConstant = 1000; + timeout.WriteTotalTimeoutMultiplier = 1000; + timeout.WriteTotalTimeoutConstant = 1000; + if (!SetCommTimeouts (comport, &timeout)) { + GPS_Serial_Error("SetCommTimeouts"); + CloseHandle (comport); + comport = INVALID_HANDLE_VALUE; + gps_errno = SERIAL_ERROR; + return 0; + } + *fd = 1; + return 1; +} + +int32 GPS_Serial_Off(const char *port, int32 fd) +{ + if (gps_is_usb) { + gusb_close(port); + } else { + CloseHandle(comport); + comport = INVALID_HANDLE_VALUE; + } + return 1; +} + +int32 GPS_Serial_Chars_Ready(int32 fd) +{ + return 1; +} + +int32 GPS_Serial_Wait(int32 fd) +{ + return 1; +} + +int32 GPS_Serial_Flush(int32 fd) +{ + return 1; +} + +int32 GPS_Serial_Write(int32 ignored, const void *obuf, int size) +{ + DWORD len; + WriteFile (comport, obuf, size, &len, NULL); + if (len != size) { + fatal ("Write error. Wrote %d of %d bytes.", len, size); + } + return len; +} + +int32 GPS_Serial_Read(int32 ignored, void *ibuf, int size) +{ + DWORD cnt = 0; + + ReadFile(comport, ibuf, size, &cnt, NULL); + return cnt; +} + +int32 GPS_Serial_Close(int32 fd, const char *port) +{ + return 1; +} + +#else + +#include +#include +#include +#include + +static struct termios gps_ttysave; + +/* @func GPS_Serial_Restoretty *********************************************** +** +** Save tty information for the serial post to be used +** +** @param [r] port [const char *] port e.g. ttyS1 +** +** @return [int32] false upon error +************************************************************************/ + +int32 GPS_Serial_Savetty(const char *port) +{ + int32 fd; + + if((fd = open(port, O_RDWR|O_NDELAY))==-1) + { + perror("open"); + gps_errno = SERIAL_ERROR; + GPS_Error("SERIAL: Cannot open serial port"); + return 0; + } + + if(tcgetattr(fd,&gps_ttysave)==-1) + { + perror("tcgetattr"); + gps_errno = HARDWARE_ERROR; + GPS_Error("SERIAL: tcgetattr error"); + return 0; + } + + + if(!GPS_Serial_Close(fd,port)) + { + gps_errno = SERIAL_ERROR; + GPS_Error("GPS_Serial_Savetty: Close error"); + return 0; + } + + return 1; +} + + +/* @func GPS_Serial_Restoretty *********************************************** +** +** Restore serial post to condition before AJBGPS called +** +** @param [r] port [const char *] port e.g. ttyS1 +** +** @return [int32] false upon error +************************************************************************/ + +int32 GPS_Serial_Restoretty(const char *port) +{ + int32 fd; + + if((fd = open(port, O_RDWR|O_NDELAY))==-1) + { + perror("open"); + gps_errno = HARDWARE_ERROR; + GPS_Error("SERIAL: Cannot open serial port"); + return 0; + } + + if(tcsetattr(fd, TCSAFLUSH, &gps_ttysave)==-1) + { + perror("ioctl"); + gps_errno = HARDWARE_ERROR; + GPS_Error("SERIAL: tcsetattr error"); + return 0; + } + + return 1; +} + + + +/* @func GPS_Serial_Open *********************************************** +** +** Open a serial port 8bits 1 stop bit 9600 baud +** +** @param [w] fd [int32 *] file descriptor +** @param [r] port [const char *] port e.g. ttyS1 +** +** @return [int32] false upon error +************************************************************************/ + +int32 GPS_Serial_Open(int32 *fd, const char *port) +{ + struct termios tty; + + /* + * This originally had O_NDELAY | O_NOCTTY in here, but this + * causes problems with Linux USB ttys (observed on PL2303 and MCT) + * and the rest of the code doesn't _REALLY_ handle the partial + * write/retry case anyway. - robertl + */ + if((*fd = open(port, O_RDWR))==-1) + { + perror("open"); + GPS_Error("SERIAL: Cannot open serial port"); + gps_errno = SERIAL_ERROR; + return 0; + } + + + if(tcgetattr(*fd,&tty)==-1) + { + perror("tcgetattr"); + GPS_Error("SERIAL: tcgetattr error"); + gps_errno = SERIAL_ERROR; + return 0; + } + + tty.c_cflag &= ~(CSIZE); + tty.c_cflag |= (CREAD | CS8 | CLOCAL); + cfsetospeed(&tty,B9600); + cfsetispeed(&tty,B9600); + + tty.c_lflag &= 0x0; + tty.c_iflag &= 0x0; + tty.c_oflag &= 0x0; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + if(tcsetattr(*fd,TCSANOW,&tty)==-1) + { + perror("tcsetattr"); + GPS_Error("SERIAL: tcsetattr error"); + return 0; + } + + return 1; +} + +int32 GPS_Serial_Read(int32 handle, void *ibuf, int size) +{ +#if GARMULATOR + static int l; + static char *rp; + char **rxp = &rxdata[l]; + char *hex; + char *rx = *rxp; + char *ib = ibuf; + + if (!rp) rp = rxdata[0]; + + /* Skip over nulls in our pasted strings */ + if (*rp == 0) { + rp = rxdata[++l]; + } + + *ib = strtoul(rp, &rp, 16); + if (*rp) rp++; + fprintf(stderr, "."); + return 1; + +#else + return read(handle, ibuf, size); +#endif +} + +int32 GPS_Serial_Write(int32 handle, const void *obuf, int size) +{ + return write(handle, obuf, size); +} + + +/* @func GPS_Serial_Flush *********************************************** +** +** Flush the serial lines +** +** @param [w] fd [int32] file descriptor +** +** @return [int32] false upon error +************************************************************************/ +int32 GPS_Serial_Flush(int32 fd) +{ + + if(tcflush(fd,TCIOFLUSH)) + { + perror("tcflush"); + GPS_Error("SERIAL: tcflush error"); + gps_errno = SERIAL_ERROR; + return 0; + } + + return 1; +} + + + +/* @func GPS_Serial_Close *********************************************** +** +** Close serial port +** +** @param [r] fd [int32 ] file descriptor +** @param [r] port [const char *] port e.g. ttyS1 +** +** @return [int32] false upon error +************************************************************************/ + +int32 GPS_Serial_Close(int32 fd, const char *port) +{ + if(close(fd)==-1) + { + perror("close"); + GPS_Error("SERIAL: Error closing serial port"); + gps_errno = SERIAL_ERROR; + return 0; + } + + return 1; +} + + +/* @func GPS_Serial_Chars_Ready ***************************************** +** +** Query port to see if characters are waiting to be read +** +** @param [r] fd [int32 ] file descriptor +** +** @return [int32] true if chars waiting +************************************************************************/ + +int32 GPS_Serial_Chars_Ready(int32 fd) +{ + fd_set rec; + struct timeval t; +#if GARMULATOR + static foo; + /* Return sporadic reads just to torment the rest of the code. */ + if ((foo++ & 0xf) == 0) + return 1; + else + return 0; +#endif + + FD_ZERO(&rec); + FD_SET(fd,&rec); + + t.tv_sec = 0; + t.tv_usec = 0; + (void) select(fd+1,&rec,NULL,NULL,&t); + if(FD_ISSET(fd,&rec)) + return 1; + + return 0; +} + + + +/* @func GPS_Serial_Wait *********************************************** +** +** Wait 80 milliseconds before testing for input. The GPS delay +** appears to be around 40-50 milliseconds. Doubling the value is to +** allow some leeway. +** +** @param [r] fd [int32 ] file descriptor +** +** @return [int32] true if serial chars waiting +************************************************************************/ + +int32 GPS_Serial_Wait(int32 fd) +{ + fd_set rec; + struct timeval t; + + if (gps_is_usb) return 1; + + FD_ZERO(&rec); + FD_SET(fd,&rec); + + t.tv_sec = 0; + t.tv_usec = usecDELAY; + + (void) select(fd+1,&rec,NULL,NULL,&t); + if(FD_ISSET(fd,&rec)) + return 1; + + return 0; +} + + + +/* @func GPS_Serial_On ***************************************** +** +** Set up port +** +** @param [r] port [const char *] port +** @param [w] fd [int32 *] file descriptor +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Serial_On(const char *port, int32 *fd) +{ + if (gps_is_usb) { + return gusb_init(); + } + if(!GPS_Serial_Savetty(port)) + { + GPS_Error("Cannot access serial port"); + gps_errno = SERIAL_ERROR; + return 0; + } + + if(!GPS_Serial_Open(fd,port)) + { + GPS_Error("Cannot open serial port"); + gps_errno = SERIAL_ERROR; + return 0; + } + + return 1; +} + + + +/* @func GPS_Serial_Off *********************************************** +** +** Done with port +** +** @param [r] port [const char *] port +** @param [r] fd [int32 ] file descriptor +** +** @return [int32] success +************************************************************************/ + +int32 GPS_Serial_Off(const char *port, int32 fd) +{ + if(!GPS_Serial_Close(fd,port)) + { + GPS_Error("Error Closing port"); + gps_errno = HARDWARE_ERROR; + return 0; + } + + if(!GPS_Serial_Restoretty(port)) + { + GPS_Error("Error restoring port"); + gps_errno = HARDWARE_ERROR; + return 0; + } + + return 1; +} + + + + + + + +/* @func GPS_Serial_Open_NMEA ****************************************** +** +** Open a serial port 8bits 1 stop bit 4800 baud +** +** @param [w] fd [int32 *] file descriptor +** @param [r] port [const char *] port e.g. ttyS1 +** +** @return [int32] false upon error +************************************************************************/ + +int32 GPS_Serial_Open_NMEA(int32 *fd, const char *port) +{ + struct termios tty; + + + if((*fd = open(port, O_RDWR | O_NDELAY | O_NOCTTY))==-1) + { + perror("open"); + GPS_Error("SERIAL: Cannot open serial port"); + gps_errno = SERIAL_ERROR; + return 0; + } + + + if(tcgetattr(*fd,&tty)==-1) + { + perror("tcgetattr"); + GPS_Error("SERIAL: tcgetattr error"); + gps_errno = SERIAL_ERROR; + return 0; + } + + + tty.c_cflag |= (CREAD | CS8 | CSIZE | CLOCAL); + cfsetospeed(&tty,B4800); + cfsetispeed(&tty,B4800); + + tty.c_lflag &= 0x0; + tty.c_iflag &= 0x0; + tty.c_oflag &= 0x0; + + + if(tcsetattr(*fd,TCSANOW,&tty)==-1) + { + perror("tcsetattr"); + GPS_Error("SERIAL: tcsetattr error"); + return 0; + } + + return 1; +} + + + + + + + +/* @func GPS_Serial_On_NMEA ******************************************** +** +** Set up port for NMEA +** +** @param [r] port [const char *] port +** @param [w] fd [int32 *] file descriptor +** +** @return [int32] success +************************************************************************/ +int32 GPS_Serial_On_NMEA(const char *port, int32 *fd) +{ + + if(!GPS_Serial_Savetty(port)) + { + GPS_Error("Cannot access serial port"); + gps_errno = SERIAL_ERROR; + return 0; + } + + if(!GPS_Serial_Open_NMEA(fd,port)) + { + GPS_Error("Cannot open serial port"); + gps_errno = SERIAL_ERROR; + return 0; + } + + return 1; +} +#endif /* __WIN32__ */ diff --git a/jeeps/gpsserial.h b/jeeps/gpsserial.h new file mode 100644 index 000000000..1849cd01c --- /dev/null +++ b/jeeps/gpsserial.h @@ -0,0 +1,33 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsserial_h +#define gpsserial_h + + +#include "gps.h" + +#define usecDELAY 180000 /* Microseconds before GPS sends A001 */ + +int32 GPS_Serial_Chars_Ready(int32 fd); +int32 GPS_Serial_Close(int32 fd, const char *port); +int32 GPS_Serial_Open(int32 *fd, const char *port); +int32 GPS_Serial_Open_NMEA(int32 *fd, const char *port); +int32 GPS_Serial_Restoretty(const char *port); +int32 GPS_Serial_Savetty(const char *port); +int32 GPS_Serial_On(const char *port, int32 *fd); +int32 GPS_Serial_Off(const char *port, int32 fd); +int32 GPS_Serial_Wait(int32 fd); +int32 GPS_Serial_Flush(int32 fd); +int32 GPS_Serial_On_NMEA(const char *port, int32 *fd); +int32 GPS_Serial_Read(int32 ignored, void *ibuf, int size); +int32 GPS_Serial_Write(int32 ignored, const void *obuf, int size); + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/gpsusbread.c b/jeeps/gpsusbread.c new file mode 100644 index 000000000..6c9284dec --- /dev/null +++ b/jeeps/gpsusbread.c @@ -0,0 +1,62 @@ +/* + Decompose an incoming USB packet to make it look like a serial one. + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "gps.h" +#include "garminusb.h" + +int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet) +{ + int32 n; + UC u; + UC *p; + int32 i; + int32 payload_size; + const char *m1; + const char *m2; + + garmin_usb_packet pkt; + memset(&pkt, 0, sizeof(pkt)); + n = gusb_cmd_get(&pkt, sizeof(pkt)); + + if (1 && gps_show_bytes) { + GPS_Diag("\nRx Data:[%d]",n); + for (i = 0; i < n; i++) + GPS_Diag("%02x ", pkt.dbuf[i]); + for (i = 0; i < n; i++) + GPS_Diag("%c", isalnum(pkt.dbuf[i]) ? pkt.dbuf[i] : '.'); + m1 = Get_Pkt_Type(pkt.gusb_pkt.pkt_id[0], pkt.gusb_pkt.databuf[0], &m2); + GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); + + } + + /* + * Populate members of serial packet from USB packet. The + * copy here seems wasteful, but teaching all the callers about + * a structure with the "data" member being in a different place + * (Since the protocol packets was badly exposed in the core + * design of jeeps) is even more painful. + */ + (*packet)->type = le_read16(&pkt.gusb_pkt.pkt_id); + payload_size = le_read32(&pkt.gusb_pkt.datasz); + (*packet)->n = payload_size; + memcpy((*packet)->data, &pkt.gusb_pkt.databuf, payload_size); + return payload_size; +} diff --git a/jeeps/gpsusbsend.c b/jeeps/gpsusbsend.c new file mode 100644 index 000000000..89fce642f --- /dev/null +++ b/jeeps/gpsusbsend.c @@ -0,0 +1,55 @@ +/* + Form GarminUSB packets to send. + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "gps.h" +#include +#include +#include "garminusb.h" + + +void GPS_Make_Packet_usb(GPS_PPacket *packet, UC type, UC *data, int16 n) +{ + garmin_usb_packet **up = (garmin_usb_packet**) packet; + + /* + * This is a little tacky that we're stuffing a garmin_usb_packet + * into a GPS_PPacket, but the packet is big enough and we have only + * a few places that really peek into this structure anyway... + */ + memset(*up, 0, sizeof **packet); + (*up)->gusb_pkt.type = 0x14; /* Garmin protocol layer */ + le_write16((*up)->gusb_pkt.pkt_id, type); + le_write32((*up)->gusb_pkt.datasz, n); + memcpy(&(*up)->gusb_pkt.databuf, data, n); + + return; +} + +int32 +GPS_Write_Packet_usb(int32 fd, GPS_PPacket packet) +{ + size_t ret, sz; + + garmin_usb_packet *gp = (garmin_usb_packet*) packet; + sz = le_read32(gp->gusb_pkt.datasz); + + return gusb_cmd_send(gp, sz + 12); +} diff --git a/jeeps/gpsusbstub.c b/jeeps/gpsusbstub.c new file mode 100644 index 000000000..04659c3ee --- /dev/null +++ b/jeeps/gpsusbstub.c @@ -0,0 +1,56 @@ +/* + Stubs to keep build happy when USB just isn't available to us. + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#if NO_USB + +#include "garminusb.h" + +const char no_usb[] = "USB suport is not available in this build.\n"; +int +gusb_cmd_send(const garmin_usb_packet *obuf, size_t sz) +{ + fatal(no_usb); +} + +int +gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz) +{ + fatal(no_usb); +} + +int +gusb_open(const char *portname) +{ + fatal(no_usb); +} + +int +gusb_init() +{ + fatal(no_usb); +} + +int +gusb_close(const char *portname) +{ + return 0; +} +#endif /* defined(NO_USB) */ diff --git a/jeeps/gpsusbwin.c b/jeeps/gpsusbwin.c new file mode 100644 index 000000000..21cd9b5d9 --- /dev/null +++ b/jeeps/gpsusbwin.c @@ -0,0 +1,296 @@ +#if !defined(NO_USB) +/* + Windows layer of Garmin/USB protocol. + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gps.h" +#include "gpsapp.h" +#include "garminusb.h" + +/* Constants from Garmin doc. */ + +// {2C9C45C2-8E7D-4C08-A12D-816BBAE722C0} +DEFINE_GUID(GARMIN_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81, 0x6b, 0xba, 0xe7, 0x22, 0xc0); + +#define GARMIN_USB_API_VERSION 1 +#define GARMIN_USB_MAX_BUFFER_SIZE 4096 +#define GARMIN_USB_INTERRUPT_DATA_SIZE 64 + +#define IOCTL_GARMIN_USB_API_VERSION CTL_CODE \ + (FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_GARMIN_USB_INTERRUPT_IN CTL_CODE \ + (FILE_DEVICE_UNKNOWN, 0x850, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_GARMIN_USB_BULK_OUT_PACKET_SIZE CTL_CODE \ + (FILE_DEVICE_UNKNOWN, 0x851, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +static HANDLE *usb_handle ; +static int usb_tx_packet_size ; + +static const char oinit[12] = {0, 0, 0, 0, 0x05, 0, 0, 0, 0, 0, 0, 0}; +garmin_usb_packet iresp; +garmin_usb_packet iresp_junk; +static int ct; + +static char * id_unit(void); + +int +gusb_open(const char *pname) +{ + int maxtries; + int maxct = 10; + int unit_number = 0; + int req_unit_number = 0; + + SP_INTERFACE_DEVICE_DATA devinterface; + PSP_INTERFACE_DEVICE_DETAIL_DATA pdd = NULL; + SP_DEVINFO_DATA devinfo; + HDEVINFO hdevinfo; + DWORD size; + if (ct++) return 1; + + if (strlen(pname) > 4) { + req_unit_number = atoi(pname+4); + GPS_Diag("Searching for USB unit number %d\n", unit_number); +// if (req_unit_number == -2) { +// printf("%d %u %s\n", 0, 3019840053, "GPSMap60CS Software Version 3.50"); +// exit(0); +// } + } + + hdevinfo = SetupDiGetClassDevs( &GARMIN_GUID, NULL, NULL, + DIGCF_PRESENT|DIGCF_INTERFACEDEVICE); + + if (hdevinfo == INVALID_HANDLE_VALUE) { + fatal("XXX"); + return 0; + } + + /* Get the device associated with this index. */ + devinterface.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA); + if (!SetupDiEnumDeviceInterfaces(hdevinfo, NULL, &GARMIN_GUID, + 0, &devinterface)) { + fatal("blah"); + return 0; + } + + SetupDiGetDeviceInterfaceDetail(hdevinfo, &devinterface, + NULL, 0, &size, NULL); + + pdd = malloc(size); + pdd->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); + devinfo.cbSize = sizeof(SP_DEVINFO_DATA); + + if (!SetupDiGetDeviceInterfaceDetail(hdevinfo, &devinterface, pdd, size, NULL, &devinfo)) { + fatal("ZZZ"); + } + + /* Whew. All that just to get something we can open... */ + GPS_Diag("Windows GUID for interface %d is \n\t%s\n", unit_number, + pdd->DevicePath); + usb_handle = CreateFile(pdd->DevicePath, GENERIC_READ|GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL ); + if (usb_handle == INVALID_HANDLE_VALUE) { + GPS_Serial_Error("CreateFile failed"); + fatal("CreateFile"); + } + + if(!DeviceIoControl(usb_handle, IOCTL_GARMIN_USB_BULK_OUT_PACKET_SIZE, NULL, 0, + &usb_tx_packet_size, GARMIN_USB_INTERRUPT_DATA_SIZE, &size, NULL)) { + fatal("Couldn't get USB packet size"); + } + + if (pdd) { + free(pdd); + } + SetupDiDestroyDeviceInfoList(hdevinfo); + + for (maxtries = maxct; maxtries; maxtries--) { + + le_write16(&iresp.gusb_pkt.pkt_id, 0); + le_write32(&iresp.gusb_pkt.datasz, 0); + le_write32(&iresp.gusb_pkt.databuf, 0); + + gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit)); + gusb_cmd_get(&iresp, sizeof(iresp)); + + if ((le_read16(iresp.gusb_pkt.pkt_id) == 6) && + (le_read32(iresp.gusb_pkt.datasz) == 4)) { + unsigned serial_number = le_read32(iresp.gusb_pkt.databuf); + GPS_Diag("Serial %u. Synced in %d\n", + serial_number, + maxct - maxtries); + garmin_unit_info[unit_number].serial_number = serial_number; + garmin_unit_info[unit_number].os_identifier = strdup(pdd->DevicePath); + garmin_unit_info[unit_number].product_identifier = id_unit(); + if (req_unit_number < 0) { + printf("%d %u %s\n", unit_number, serial_number, garmin_unit_info[unit_number].product_identifier); + return 2; + } + return 1; + } + } + fatal("Unable to establish USB syncup within %d tries.\n", maxct); + return 0; +} + +int +gusb_close(const char *portname) +{ + if (usb_handle != INVALID_HANDLE_VALUE) { +#if 0 + /* FIXME: we should probably release things and delete the "ct" + * reference count above... + */ + CloseHandle(usb_handle); + usb_handle = INVALID_HANDLE_VALUE; +#endif + } +} + +int +gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz) +{ + DWORD rxed = GARMIN_USB_INTERRUPT_DATA_SIZE; + unsigned char *buf = &ibuf->dbuf; + int i; + int tsz=0; + unsigned char *obuf = buf; + + while (sz) { + /* The driver wrongly (IMO) rejects reads smaller than + * GARMIN_USB_INTERRUPT_DATA_SIZE + */ + if(!DeviceIoControl(usb_handle, IOCTL_GARMIN_USB_INTERRUPT_IN, NULL, 0, + buf, GARMIN_USB_INTERRUPT_DATA_SIZE, &rxed, NULL)) { + GPS_Serial_Error("Ioctl"); + fatal("ioctl"); + } + buf += rxed; + sz =- rxed; + tsz += rxed; + if (rxed < GARMIN_USB_INTERRUPT_DATA_SIZE) { + break; + } + } + + if (gps_show_bytes) { + const char *m1, *m2; + printf("RX [%d]:", tsz); + for(i=0;igusb_pkt.pkt_id[0], ibuf->gusb_pkt.databuf[0], &m2); + GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); + printf("\n"); + } + return tsz; +} + +int +gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz) +{ + DWORD rsz; + size_t i; + unsigned char *obuf = &opkt->dbuf; + const char *m1, *m2; + + /* The spec warns us about making writes an exact multiple + * of the packet size, but isn't clear whether we can issue + * data in a single call to WriteFile if it spans buffers. + */ + WriteFile(usb_handle, obuf, sz, &rsz, NULL); + if (gps_show_bytes) { + printf("TX [%d]:", rsz); + for(i=0;igusb_pkt.pkt_id[0], opkt->gusb_pkt.databuf[0], &m2); + GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); + } + + if (rsz != sz) { + fatal ("Error sending %d bytes. Successfully sent %d\n", sz, rsz); + } + + if (0 == sz % usb_tx_packet_size) { + DWORD sz2; + GPS_Diag("Writing padding buffer.\n"); + WriteFile(usb_handle, 0, 0, &sz2, NULL); + } + + return rsz; +} + +static char * +id_unit(void) +{ +static const char oid[12] = {20, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, 0, 0}; + /* + * Identify the unit before getting into all the protocol gunk. + * We get two packets back, but we discard the protocol array + * for now. + */ + + gusb_cmd_send((garmin_usb_packet *)oid, sizeof(oid)); + gusb_cmd_get(&iresp, sizeof(iresp)); + gusb_cmd_get(&iresp_junk, sizeof(iresp_junk)); + + if (iresp.gusb_pkt.type == 20 && + le_read16(iresp.gusb_pkt.pkt_id) == 0xff) { + return strdup(iresp.gusb_pkt.databuf+4); + } + + return NULL; +} + + +#if 0 +main() +{ + DWORD sz; +char ocmd[] = {00, 00, 00, 00, 05, 00, 00, 00, 00, 00, 00, 00}; +char ocmd2[] = {0x14, 00, 00, 00, 0xfe, 00, 00, 00, 00, 00, 00, 00}; + gusb_open(); + WriteFile(usb_handle, ocmd, sizeof(ocmd), &sz, NULL); + printf("Wrote %d\n", sz); + usb_intr_get(); + + WriteFile(usb_handle, ocmd2, sizeof(ocmd2), &sz, NULL); + printf("Wrote %d\n", sz); + usb_intr_get(); + + WriteFile(usb_handle, ocmd2, sizeof(ocmd2), &sz, NULL); + printf("Wrote %d\n", sz); + usb_intr_get(); +} +#endif +#endif /* !defined(NO_USB) */ diff --git a/jeeps/gpsutil.c b/jeeps/gpsutil.c new file mode 100644 index 000000000..7311d019a --- /dev/null +++ b/jeeps/gpsutil.c @@ -0,0 +1,691 @@ +/******************************************************************** +** @source JEEPS utility functions +** +** @author Copyright (C) 1999 Alan Bleasby +** @version 1.0 +** @modified Dec 28 1999 Alan Bleasby. First version +** @@ +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +********************************************************************/ +#include "gps.h" +#include +#include +#include + +static int32 gps_endian_called=0; +static int32 GPS_Little=0; + +int32 gps_warning = 0; +int32 gps_error = 0; +int32 gps_user = 0; +int32 gps_show_bytes = 0; +int32 gps_errno = 0; + +/* @func GPS_Util_Little *********************************************** +** +** Determine endian nature of host +** +** @return [int32] true if little-endian +************************************************************************/ + +int32 GPS_Util_Little(void) +{ + static union lb + { + char chars[sizeof(int32)]; + int32 i; + } + data; + + if(!gps_endian_called) + { + gps_endian_called = 1; + data.i = 0; + *data.chars = '\1'; + if(data.i == 1) + GPS_Little = 1; + else + GPS_Little = 0; + } + + return GPS_Little; +} + + +/* @func GPS_Util_Get_Short ******************************************** +** +** Get a short from a string +** +** @return [US] value +************************************************************************/ + +US GPS_Util_Get_Short(const UC *s) +{ + static US ret; + UC *p; + + p = (UC *)&ret; + + if(!GPS_Little) + { + *p++ = *(s+1); + *p = *s; + } + else + { + *p++ = *s; + *p = *(s+1); + } + + return ret; +} + + + +/* @func GPS_Util_Put_Short ******************************************** +** +** Put a short to a string +** +** @param [w] s [UC *] string to write to +** @param [r] v [const US] short to write +** +** @return [void] +************************************************************************/ + +void GPS_Util_Put_Short(UC *s, const US v) +{ + UC *p; + + p = (UC *)&v; + + if(!GPS_Little) + { + *s++ = *(p+1); + *s = *p; + } + else + { + *s++ = *p; + *s = *(p+1); + } + + return; +} + + + +/* @func GPS_Util_Get_Double ******************************************** +** +** Get a double from a string +** +** @return [double] value +************************************************************************/ + +double GPS_Util_Get_Double(const UC *s) +{ + double ret; + UC *p; + int32 i; + + p = (UC *)&ret; + + + if(!GPS_Little) + for(i=sizeof(double)-1;i>-1;--i) + *p++ = s[i]; + else + for(i=0;i<(int32)sizeof(double);++i) + *p++ = s[i]; + + return ret; +} + + + +/* @func GPS_Util_Put_Double ******************************************** +** +** Put a double to a string +** +** @param [w] s [UC *] string to write to +** @param [r] v [const double] double to write +** +** @return [void] +************************************************************************/ + +void GPS_Util_Put_Double(UC *s, const double v) +{ + UC *p; + int32 i; + + p = (UC *)&v; + + if(!GPS_Little) + for(i=sizeof(double)-1;i>-1;--i) + s[i] = *p++; + else + for(i=0;i<(int32)sizeof(double);++i) + s[i] = *p++; + + return; +} + + + + +/* @func GPS_Util_Get_Int ******************************************** +** +** Get an int from a string +** +** @return [int32] value +************************************************************************/ + +int32 GPS_Util_Get_Int(const UC *s) +{ + int32 ret; + UC *p; + int32 i; + + p = (UC *)&ret; + + + if(!GPS_Little) + for(i=sizeof(int32)-1;i>-1;--i) + *p++ = s[i]; + else + for(i=0;i<(int32)sizeof(int32);++i) + *p++ = s[i]; + + return ret; +} + + + +/* @func GPS_Util_Put_Int ******************************************** +** +** Put a int to a string +** +** @param [w] s [UC *] string to write to +** @param [r] v [const int32] int to write +** +** @return [void] +************************************************************************/ + +void GPS_Util_Put_Int(UC *s, const int32 v) +{ + UC *p; + int32 i; + + p = (UC *)&v; + + if(!GPS_Little) + for(i=sizeof(int32)-1;i>-1;--i) + s[i] = *p++; + else + for(i=0;i<(int32)sizeof(int32);++i) + s[i] = *p++; + + return; +} + + + +/* @func GPS_Util_Get_Uint ******************************************** +** +** Get an unsigned int from a string +** +** @return [uint32] value +************************************************************************/ + +uint32 GPS_Util_Get_Uint(const UC *s) +{ + uint32 ret; + UC *p; + int32 i; + + p = (UC *)&ret; + + + if(!GPS_Little) + for(i=sizeof(uint32)-1;i>-1;--i) + *p++ = s[i]; + else + for(i=0;i<(int32)sizeof(uint32);++i) + *p++ = s[i]; + + return ret; +} + + + +/* @func GPS_Util_Put_Uint ******************************************** +** +** Put an unisgned int to a string +** +** @param [w] s [UC *] string to write to +** @param [r] v [const uint32] unsigned int to write +** +** @return [void] +************************************************************************/ + +void GPS_Util_Put_Uint(UC *s, const uint32 v) +{ + UC *p; + int32 i; + + p = (UC *)&v; + + if(!GPS_Little) + for(i=sizeof(uint32)-1;i>-1;--i) + s[i] = *p++; + else + for(i=0;i<(int32)sizeof(uint32);++i) + s[i] = *p++; + + return; +} + + + +/* @func GPS_Util_Get_Float ******************************************** +** +** Get a float from a string +** +** @return [float] value +************************************************************************/ + +float GPS_Util_Get_Float(const UC *s) +{ + float ret; + UC *p; + int32 i; + + p = (UC *)&ret; + + + if(!GPS_Little) + for(i=sizeof(float)-1;i>-1;--i) + *p++ = s[i]; + else + for(i=0;i<(int32)sizeof(float);++i) + *p++ = s[i]; + + return ret; +} + + + +/* @func GPS_Util_Put_Float ******************************************** +** +** Put a float to a string +** +** @param [w] s [UC *] string to write to +** @param [r] v [const float] float to write +** +** @return [void] +************************************************************************/ + +void GPS_Util_Put_Float(UC *s, const float v) +{ + UC *p; + int32 i; + + p = (UC *)&v; + + if(!GPS_Little) + for(i=sizeof(float)-1;i>-1;--i) + s[i] = *p++; + else + for(i=0;i<(int32)sizeof(float);++i) + s[i] = *p++; + + return; +} + +#if 0 +/* @func GPS_Util_Canon **************************************************** +** +** Sets or unsets canonical mode +** NB: Must have called this with True before calling with False +** NB: Remember to trun it off (false) eventually +** +** @param [r] state [int32] state=true->raw state=false->normal +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Util_Canon(int32 state) +{ + static struct termios tty; + static struct termios sv; + + + if(state) + { + tcgetattr(1,&sv); + tcgetattr(1, &tty); + tty.c_cc[VMIN]='\1'; + tty.c_cc[VTIME]='\0'; + tcsetattr(1,TCSANOW,&tty); + tty.c_lflag &= ~(ICANON | ECHO); + tcsetattr(1, TCSANOW, &tty); + } + else + tcsetattr(1, TCSANOW, &sv); + + return; +} +#endif + +#if 0 +/* @func GPS_Util_Block **************************************************** +** +** Sets or unsets blocking +** @modified 13-01-2000 to return an int +** +** @param [r] fd [int32] file descriptor +** @param [r] state [int32] state=true->block state=false->non-block +** +** @return [int32] success +** @@ +****************************************************************************/ + +int32 GPS_Util_Block(int32 fd, int32 state) +{ + static int32 notcalled=1; + static int32 block; + static int32 noblock; + int32 f; + + gps_errno = HARDWARE_ERROR; + + if(notcalled) + { + notcalled = 0; + if((f=fcntl(fd,F_GETFL,0))==-1) + { + GPS_Error("Util_Block: FCNTL error"); + return 0; + } + block = f & ~O_NDELAY; + noblock = f | O_NDELAY; + } + + if(state) + { + if(fcntl(fd,F_SETFL,block)==-1) + { + GPS_Error("Util_Block: Error blocking"); + return 0; + } + } + else + { + if(fcntl(fd,F_SETFL,noblock)==-1) + { + GPS_Error("Util_Block: Error unblocking"); + return 0; + } + } + + return 1; +} +#endif + + +/* @func GPS_Warning ******************************************************** +** +** Prints warning if gps_warning is true +** +** @param [r] s [char *] warning +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Warning(char *s) +{ + if(!gps_warning) + return; + + fprintf(stderr,"[WARNING] %s\n",s); + fflush(stderr); + + return; +} + + +/* @func GPS_Fatal ******************************************************** +** +** Always prints error and exits program +** Bad thing for a library so the library doesn't call it. +** +** @param [r] s [char *] fatal error +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Fatal(char *s) +{ + + fprintf(stderr,"[FATAL] %s\n",s); + exit(0); + return; +} + + + +/* @func GPS_Error ********************************************************** +** +** Prints Error if gps_error is true +** +** @param [r] s [char *] error +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Error(char *s) +{ + if(!gps_error) + return; + + fprintf(stderr,"[ERROR] %s\n",s); + fflush(stderr); + + return; +} + + +/* @func GPS_Enable_Error *************************************************** +** +** Enable error message printing +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Enable_Error(void) +{ + gps_error = 1; + return; +} + + + +/* @func GPS_Enable_Warning *************************************************** +** +** Enable warning message printing +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Enable_Warning(void) +{ + gps_warning = 1; + return; +} + + + +/* @func GPS_Disable_Error *************************************************** +** +** Disable error message printing +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Disable_Error(void) +{ + gps_error = 0; + return; +} + + + +/* @func GPS_Disable_Warning *********************************************** +** +** Disable warning message printing +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Disable_Warning(void) +{ + gps_warning = 0; + return; +} + + + +/* @func GPS_User ******************************************************** +** +** Prints a message if gps_user is true +** +** @param [r] s [char *] message +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_User(char *s) +{ + if(!gps_user) + return; + + fprintf(stdout,"%s\n",s); + fflush(stdout); + + return; +} + +/* @func GPS_Disable_User *********************************************** +** +** Disable message printing +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Disable_User(void) +{ + gps_user = 0; + return; +} + + +/* @func GPS_Enable_User *********************************************** +** +** Disable warning message printing +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Enable_User(void) +{ + gps_user = 1; + return; +} + + +/* @func GPS_Diagnose ******************************************************** +** +** Prints bytes read from gps if gps_show_bytes is set +** +** @param [r] cs [int32] byte read +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Diagnose(int32 c) +{ + if(!gps_show_bytes) + return; + + fprintf(stdout,"%d\n",(int)c); + fflush(stdout); + + return; +} + +void GPS_Diag(const char *fmt, ...) +{ + va_list argp; + va_start(argp, fmt); + + if(gps_show_bytes) { + vfprintf(stdout, fmt, argp); + } + va_end(argp); + return; + +} + +/* @func GPS_Enable_Diagnose *********************************************** +** +** Enable diagnosis mode +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Enable_Diagnose(void) +{ + gps_show_bytes = 1; + return; +} + + + +/* @func GPS_Disble_Diagnose *********************************************** +** +** Disable diagnosis mode +** +** @return [void] +** @@ +****************************************************************************/ + +void GPS_Disable_Diagnose(void) +{ + gps_show_bytes = 0; + return; +} diff --git a/jeeps/gpsutil.h b/jeeps/gpsutil.h new file mode 100644 index 000000000..30027885c --- /dev/null +++ b/jeeps/gpsutil.h @@ -0,0 +1,48 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsutil_h +#define gpsutil_h + + +#include "gps.h" + +int32 GPS_Util_Little(void); + +US GPS_Util_Get_Short(const UC *s); +void GPS_Util_Put_Short(UC *s, const US v); +int32 GPS_Util_Get_Int(const UC *s); +void GPS_Util_Put_Int(UC *s, const int32 v); +double GPS_Util_Get_Double(const UC *s); +void GPS_Util_Put_Double(UC *s, const double v); +float GPS_Util_Get_Float(const UC *s); +void GPS_Util_Put_Float(UC *s, const float v); +void GPS_Util_Canon(int32 state); +int32 GPS_Util_Block(int32 fd, int32 state); +void GPS_Util_Put_Uint(UC *s, const uint32 v); +uint32 GPS_Util_Get_Uint(const UC *s); + +void GPS_Warning(char *s); +void GPS_Error(char *s); +void GPS_Fatal(char *s); +void GPS_Enable_Error(void); +void GPS_Enable_Warning(void); +void GPS_Disable_Error(void); +void GPS_Disable_Warning(void); +void GPS_User(char *s); +void GPS_Disable_User(void); +void GPS_Enable_User(void); +void GPS_Diagnose(int32 c); +void GPS_Diag(const char *fmt, ...); + +void GPS_Enable_Diagnose(void); +void GPS_Disable_Diagnose(void); + + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/jeeps/main.c b/jeeps/main.c new file mode 100644 index 000000000..a8488248b --- /dev/null +++ b/jeeps/main.c @@ -0,0 +1,31 @@ +#include "gps.h" +// #include "jeeps.h" + +main() +{ + int n; + GPS_PWay *way; + GPS_PWay *array; + + if (GPS_Init("/dev/ttyS0") < 0) { + fprintf(stderr, "Can't init\n"); + } + + if((n=GPS_Command_Get_Waypoint("/dev/ttyS0", &way))<0) { + fprintf(stderr, "can't get\n"); + return; + } +// fprintf(stdout," Done\n"); + + GPS_Fmt_Print_Waypoint(way, n, stdout); + + array = (GPS_PWay *) calloc(1, sizeof(GPS_PWay)); + array[0] = GPS_Way_New(); + strcpy(array[0]->ident,"lower @#$%^&* rocks"); + strcpy(array[0]->cmnt,"COMMENTCOMMENTCOMMENTCOMMENTCOMMENT"); + array[0]->wpt_class = 0; + array[0]->lat = 1.234; + array[0]->lon = 1.234; +GPS_Command_Send_Waypoint("/dev/ttyS0", array, 1); + +} diff --git a/macgpsbabel/Credits.rtf b/macgpsbabel/Credits.rtf new file mode 100644 index 000000000..a133febb1 --- /dev/null +++ b/macgpsbabel/Credits.rtf @@ -0,0 +1,47 @@ +{\rtf1\mac\ansicpg10000\cocoartf102 +{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural + +\f0\b\fs24 \cf0 Acknowledgements. +\f1\b0 \ +\ + +\f0\b Gpsbabel +\f1\b0 is an open-source project created and administrated by +\f0\b Robert Lipe +\f1\b0 .\ + +\f0\b MacGPSBabel +\f1\b0 is a GUI front-end for gpsbabel. It was designed by +\f0\b Jeremy Atherton +\f1\b0 .\ +\ +Thanks to the many people who have tested MacGPSBabel and given suggestions for improvement.\ +\ + +\f0\b Legal. +\f1\b0 \ +\ +Gpsbabel and MacGPSBabel are free software; you can redistribute them and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.\ +\ +Gpsbabel and MacGPSBabel are distributed in the hope that they will be useful, but +\f0\b WITHOUT ANY WARRANTY +\f1\b0 ; without even the implied warranty of +\f0\b MERCHANTABILITY +\f1\b0 or +\f0\b FITNESS FOR A PARTICULAR PURPOSE +\f1\b0 . See the GNU General Public License for more details.\ +\ +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA\ +\ + +\f0\b Gpsbabel/MacGPSBabel \'a9 2002 - 2004 +\f1\b0 +\f0\b Robert Lipe +\f1\b0 \ +\ +\ +For questions or comments regarding MacGPSBabel please visit http://gpsbabel.souceforge.net/ and use the gpsbabel-misc email list. Alternatively you can contact Jeremy Atherton through the address posted at the sourceforge site.\ +\ +If you would like to contribute your programming skills to either gpsbabel or MacGPSBabel please do. Join the gpsbabel-code email list and get involved.} \ No newline at end of file diff --git a/macgpsbabel/English.lproj/InfoPlist.strings b/macgpsbabel/English.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..32e87ed4e6a9cb78476161aa5cf611f423bfc86f GIT binary patch literal 616 zcmcJMO-sW-6h+V4Uop5WT5Aco5H}XAf)+90R@x^0z&0&u6!gcdXHuyk5pf~I%gemE zGwl4^GZ%;?b%$iv9h8t2lK@5mAi@mZPqn@LuK_*^h=Fu`R1Oh z#|7s+iO$63419lS4xAbL+_)dp=ay95kdbE#>!%HOQ)YH7?Q}2di&bi+lwra2mv_JG z2^_1SYa~3>y(>9%II)%(9ar)Lo4y>Xoe%%b;Xq|Q)vxt8YMtsubbQOP%i)e~;7(lh mF*+5eI`>xosbZkdm(F9U&O&5v&T8M|becMB=hSra$KD^dqGTNa literal 0 HcmV?d00001 diff --git a/macgpsbabel/English.lproj/MainMenu.nib/classes.nib b/macgpsbabel/English.lproj/MainMenu.nib/classes.nib new file mode 100644 index 000000000..b9b4b09f6 --- /dev/null +++ b/macgpsbabel/English.lproj/MainMenu.nib/classes.nib @@ -0,0 +1,4 @@ +{ + IBClasses = ({CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }); + IBVersion = 1; +} \ No newline at end of file diff --git a/macgpsbabel/English.lproj/MainMenu.nib/data.dependency b/macgpsbabel/English.lproj/MainMenu.nib/data.dependency new file mode 100644 index 000000000..82ceab424 --- /dev/null +++ b/macgpsbabel/English.lproj/MainMenu.nib/data.dependency @@ -0,0 +1,10 @@ + + + + + IBPaletteDependency + + ASKPalette + + + diff --git a/macgpsbabel/English.lproj/MainMenu.nib/info.nib b/macgpsbabel/English.lproj/MainMenu.nib/info.nib new file mode 100644 index 000000000..0f6ae32f9 --- /dev/null +++ b/macgpsbabel/English.lproj/MainMenu.nib/info.nib @@ -0,0 +1,25 @@ + + + + + IBDocumentLocation + 69 10 356 240 0 0 1152 746 + IBEditorPositions + + 29 + 69 252 302 44 0 0 1152 746 + + IBFramework Version + 364.0 + IBOpenObjects + + 305 + 229 + 21 + 678 + 29 + + IBSystem Version + 7M34 + + diff --git a/macgpsbabel/English.lproj/MainMenu.nib/objects.nib b/macgpsbabel/English.lproj/MainMenu.nib/objects.nib new file mode 100644 index 0000000000000000000000000000000000000000..92e08d284a77bdadf4f0ff7af0b236f7215d07e7 GIT binary patch literal 22015 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 KU3irvo&Imsj|yG@ literal 0 HcmV?d00001 diff --git a/macgpsbabel/MacGPSBabel.applescript b/macgpsbabel/MacGPSBabel.applescript new file mode 100644 index 000000000..1aee120cc --- /dev/null +++ b/macgpsbabel/MacGPSBabel.applescript @@ -0,0 +1,839 @@ +-- MacGPSBabel: MacGPSBabel.applescript + +-- File created by Jeremy Atherton on Sunday, September 28, 2003. +-- Last modified by Jeremy Atherton on Tuesday, September 7, 2004. + +-- MacGPSBabel is part of the gpsbabel project and is Copyright (c) 2004 Robert Lipe. +-- see http://gpsbabel.sourceforge.net/ for more details + +-- PROPERTIES AND GLOBALS -- +property fileList : {} +property startIndex : 0 +property startState : false +global theFiles, typeList, extList, aFile + +-- EVENT HANDLERS -- + +-- Start up scripts + +-- make empty entries in user defaults +on will finish launching theObject + make new default entry at end of default entries of user defaults with properties {name:"theInputType", contents:startIndex} + make new default entry at end of default entries of user defaults with properties {name:"theOutputType", contents:startIndex} + make new default entry at end of default entries of user defaults with properties {name:"gpsIN", contents:startState} + make new default entry at end of default entries of user defaults with properties {name:"gpsOUT", contents:startState} + make new default entry at end of default entries of user defaults with properties {name:"gpsReceiver", contents:startIndex} +end will finish launching + +on awake from nib theObject + log "awake from nib - " & name of theObject + if theObject is window "MacGPSBabel" then + -- get supported file types from gpsbabel and use these to populate the file types popup lists + tell window "MacGPSBabel" + set popList to my getFormats() + repeat with i in popList + make new menu item at the end of menu items of menu of popup button "inPop" with properties {title:i, enabled:true} + make new menu item at the end of menu items of menu of popup button "outPop" with properties {title:i, enabled:true} + end repeat + end tell + + -- read current user defaults and set window controls as needed + my readSettings() + + -- deal with changes to MacGPSBabel window needed if any of the GPS check boxes are checked by default + if state of button "GPSswitchIN" of window "MacGPSBabel" is equal to 1 then + my gpsIN() + end if + if state of button "GPSswitchOUT" of window "MacGPSBabel" is equal to 1 then + my gpsOUT() + end if + end if +end awake from nib + +-- Deal with the opening and closing of windows + +on will open theObject + log "will open - " & name of theObject + -- Main Window + if theObject is window "MacGPSBabel" then + -- set the progress indicator style + set p to progress indicator 1 of theObject + call method "setStyle:" of p with parameter 1 + call method "setDisplayedWhenStopped:" of p with parameters {false} + end if + + -- Select GPS Window + if theObject is window "SelectGPS" then + -- get the list of available serial ports + set popList to my getSerial() + -- use popList to populate the drop-down menu + delete every menu item of menu of popup button "serialPop" of window "SelectGPS" + repeat with i in popList + make new menu item at the end of menu items of menu of popup button "serialPop" of window "SelectGPS" with properties {title:i, enabled:true} + end repeat + + -- read user defaults for this window + tell user defaults + set defaultgpsReceiver to contents of default entry "gpsReceiver" + end tell + set state of popup button "gpsPop" of window "SelectGPS" to defaultgpsReceiver + + -- hide MacGPSBabel window + set visible of window "MacGPSBabel" to false + end if + +end will open + +on will close theObject + log "will close - " & name of theObject + if theObject is window "SelectGPS" then + -- store user defaults for this window + set newReceiverIndex to contents of popup button "gpsPop" of window "SelectGPS" as integer + tell user defaults + set contents of default entry "gpsReceiver" to newReceiverIndex + end tell + + -- unhide MacGPSBabel window + set visible of window "MacGPSBabel" to true + end if +end will close + + +-- handler for the File>Open menu item +on choose menu item theObject + log "choose menu item - " & name of theObject + if name of theObject is "open" then + if visible of window "MacGPSBabel" is true then + if contents of text field "inputFile" of window "MacGPSBabel" is equal to "" then + my selectFile() + return 0 + else if the title of current menu item of popup button "inPop" of window "MacGPSBabel" = "Select Input File Type" then + display dialog "Please select an input file type for the previous file before adding another file" buttons {"OK"} default button 1 + return 0 + else if item 1 of (the last item in fileList) is not equal to (contents of text field "inputFile" of window "MacGPSBabel") then + set the end of fileList to {contents of text field "inputFile" of window "MacGPSBabel", contents of popup button "inPop" of window "MacGPSBabel"} + end if + my addFile() + else + set visible of window "MacGPSBabel" to true + if contents of text field "inputFile" of window "MacGPSBabel" is equal to "" then + my selectFile() + return 0 + else if the title of current menu item of popup button "inPop" of window "MacGPSBabel" = "Select Input File Type" then + display dialog "Please select an input file type for the previous file before adding another file" buttons {"OK"} default button 1 + return 0 + else if item 1 of (the last item in fileList) is not equal to (contents of text field "inputFile" of window "MacGPSBabel") then + set the end of fileList to {contents of text field "inputFile" of window "MacGPSBabel", contents of popup button "inPop" of window "MacGPSBabel"} + end if + my addFile() + end if + end if +end choose menu item + +-- HANDLERS FOR BUTTON CLICKS + +on clicked theObject + log "clicked - " & name of theObject + + -- MAIN WINDOW - Select File button + if theObject is the button "selectButton" of window "MacGPSBabel" then + if contents of text field "inputFile" of window "MacGPSBabel" is equal to "" then + my selectFile() + return 0 + else if the title of current menu item of popup button "inPop" of window "MacGPSBabel" = "Select Input File Type" then + display dialog "Please select an input file type for the previous file before adding another file" buttons {"OK"} default button 1 + return 0 + else if fileList is equal to {} or item 1 of (the last item in fileList) is not equal to (contents of text field "inputFile" of window "MacGPSBabel") then + set the end of fileList to {contents of text field "inputFile" of window "MacGPSBabel", contents of popup button "inPop" of window "MacGPSBabel"} + end if + my addFile() + end if + + -- MAIN WINDOW - Clear button + if theObject is the button "clearButton" of window "MacGPSBabel" then + my clearFiles() + end if + + -- MAIN WINDOW - Send button + if theObject is the button "sendButton" of window "MacGPSBabel" then + if state of button "GPSswitchIN" of window "MacGPSBabel" = 1 then + set fileList to {} + else if fileList is equal to {} or item 1 of (the last item in fileList) is not equal to (contents of text field "inputFile" of window "MacGPSBabel") then + set the end of fileList to {contents of text field "inputFile" of window "MacGPSBabel", contents of popup button "inPop" of window "MacGPSBabel"} + end if + my sendFile(fileList) + end if + + -- MAIN WINDOW - Use GPS radio buttons + if theObject is the button "GPSswitchIN" of window "MacGPSBabel" then + my GPSSwitchIN() + if (state of button "GPSswitchIN" of window "MacGPSBabel" = 1) and (state of button "GPSswitchOUT" of window "MacGPSBabel" = 1) then + set state of button "GPSswitchOUT" of window "MacGPSBabel" to 0 + my GPSswitchOUT() + end if + end if + if theObject is the button "GPSswitchOUT" of window "MacGPSBabel" then + my GPSswitchOUT() + if (state of button "GPSswitchOUT" of window "MacGPSBabel" = 1) and (state of button "GPSswitchIN" of window "MacGPSBabel" = 1) then + set state of button "GPSswitchIN" of window "MacGPSBabel" to 0 + my GPSSwitchIN() + end if + end if + + -- MAIN WINDOW - Filters button + if theObject is the button "filterButton" of window "MacGPSBabel" then + my showFilters() + end if + + -- MAIN WINDOW - Set As Defaults Button + if theObject is button "defaultsButton" of window "MacGPSBabel" then + set newInputIndex to contents of popup button "inPop" of window "MacGPSBabel" + set newOutputIndex to contents of popup button "outPop" of window "MacGPSBabel" + set newINstate to state of button "GPSswitchIN" of window "MacGPSBabel" as boolean + set newOUTstate to state of button "GPSswitchOUT" of window "MacGPSBabel" as boolean + tell user defaults + set contents of default entry "theInputType" to newInputIndex + set contents of default entry "theOutputType" to newOutputIndex + set contents of default entry "gpsIN" to newINstate + set contents of default entry "gpsOUT" to newOUTstate + end tell + end if + + -- GPS Receiver Window - Continue button + if theObject is the button "contButton" of window "SelectGPS" then + if the state of button "GPSswitchIN" of window "MacGPSBabel" = 1 then + my downloadFile() + else + my uploadFile(fileList) + end if + end if + + -- GPS Receiver Window - Cancel button + if theObject is the button "cancelButton" of window "SelectGPS" then + close window "SelectGPS" + end if + + -- Filter Window - Distance filter check box + if theObject is the button "distanceFilter" of window "filterWindow" then + if state of button "distanceFilter" of window "filterWindow" is equal to 1 then + set enabled of text field "dist1" of window "filterWindow" to true + set editable of text field "dist1" of window "filterWindow" to true + set enabled of popup button "dist1Select" of window "filterWindow" to true + tell window "filterWindow" + set first responder to text field "dist1" + end tell + else + set enabled of text field "dist1" of window "filterWindow" to false + set editable of text field "dist1" of window "filterWindow" to false + set enabled of popup button "dist1Select" of window "filterWindow" to false + end if + end if + + -- Filter Window - Radius Filter check box + if theObject is the button "radiusFilter" of window "filterWindow" then + if state of button "radiusFilter" of window "filterWindow" is equal to 1 then + set enabled of text field "dist2" of window "filterWindow" to true + set editable of text field "dist2" of window "filterWindow" to true + set enabled of popup button "dist2Select" of window "filterWindow" to true + set enabled of popup button "nsSelect" of window "filterWindow" to true + set enabled of popup button "ewSelect" of window "filterWindow" to true + set enabled of text field "nDeg" of window "filterWindow" to true + set editable of text field "nDeg" of window "filterWindow" to true + set enabled of text field "nMin" of window "filterWindow" to true + set editable of text field "nMin" of window "filterWindow" to true + set enabled of text field "wDeg" of window "filterWindow" to true + set editable of text field "wDeg" of window "filterWindow" to true + set enabled of text field "wMin" of window "filterWindow" to true + set editable of text field "wMin" of window "filterWindow" to true + tell window "filterWindow" + set first responder to text field "dist2" + end tell + else + set enabled of text field "dist2" of window "filterWindow" to false + set editable of text field "dist2" of window "filterWindow" to false + set enabled of popup button "dist2Select" of window "filterWindow" to false + set enabled of popup button "nsSelect" of window "filterWindow" to false + set enabled of popup button "ewSelect" of window "filterWindow" to false + set enabled of text field "nDeg" of window "filterWindow" to false + set editable of text field "nDeg" of window "filterWindow" to false + set enabled of text field "nMin" of window "filterWindow" to false + set editable of text field "nMin" of window "filterWindow" to false + set enabled of text field "wDeg" of window "filterWindow" to false + set editable of text field "wDeg" of window "filterWindow" to false + set enabled of text field "wMin" of window "filterWindow" to false + set editable of text field "wMin" of window "filterWindow" to false + end if + end if + + -- Filter Window - Arc filter check box + if theObject is the button "arcSwitch" of window "filterWindow" then + if state of button "arcSwitch" of window "filterWindow" is equal to 1 then + try + set fFile to choose file with prompt "Select an arc filter file" + on error + set state of button "arcSwitch" of window "filterWindow" to 0 + return 0 + end try + set contents of text field "arcFile" of window "filterWindow" to POSIX path of fFile as string + set enabled of text field "arcDist" of window "filterWindow" to true + set editable of text field "arcDist" of window "filterWindow" to true + set enabled of popup button "arcUnits" of window "filterWindow" to true + else + set contents of text field "arcFile" of window "filterWindow" to "" + set contents of text field "arcDist" of window "filterWindow" to "" + set enabled of text field "arcDist" of window "filterWindow" to false + set editable of text field "arcDist" of window "filterWindow" to false + set enabled of popup button "arcUnits" of window "filterWindow" to false + end if + end if + + -- Filter Window - polygon filter check box + if theObject is the button "polySwitch" of window "filterWindow" then + if state of button "polySwitch" of window "filterWindow" is equal to 1 then + try + set pFile to choose file with prompt "Select a polygon filter file" + on error + set state of button "polySwitch" of window "filterWindow" to 0 + return 0 + end try + set contents of text field "polyFile" of window "filterWindow" to POSIX path of pFile as string + else + set contents of text field "polyFile" of window "filterWindow" to "" + end if + end if + + -- Filter Window - Smart names check box + if theObject is the button "smartSwitch" of window "filterWindow" then + if state of button "smartSwitch" of window "filterWindow" is equal to 1 then + set enabled of text field "smartLen" of window "filterWindow" to true + set editable of text field "smartLen" of window "filterWindow" to true + set contents of text field "smartLen" of window "filterWindow" to "" + else + set enabled of text field "smartLen" of window "filterWindow" to false + set editable of text field "smartLen" of window "filterWindow" to false + end if + end if + + --debug mode + if theObject is the button "debugButton" of window "MacGPSBabel" then + if (visible of window "debugWindow") is false then + set visible of window "debugWindow" to true + else + set visible of window "debugWindow" to false + end if + end if + if theObject is the button "executeButton" of window "debugWindow" then + set theScript to contents of text field "debugInput" of window "debugWindow" + if theScript starts with "gpsbabel" then + set thePath to quoted form of (POSIX path of (path to me) as string) & "Contents/Resources/" + set theScript to thePath & theScript + end if + set theOutput to do shell script theScript as string + set the contents of text view 1 of scroll view 1 of window "debugWindow" to "" + set the contents of text view 1 of scroll view 1 of window "debugWindow" to theOutput + end if + +end clicked + + +-- MY HANDLERS -- + + +-- SCRIPTS FOR CHOOSING THE INPUT FILE +-- select the first file +on selectFile() + -- Choose a file (using the open file dialog box) + set aFile to choose file with prompt "Select an input file" + set contents of text field "inputFile" of window "MacGPSBabel" to aFile + if contents of text field "inputFile" of window "MacGPSBabel" is not equal to "" then + set key equivalent of button "selectButton" of window "MacGPSBabel" to "" + set enabled of button "sendButton" of window "MacGPSBabel" to true + set enabled of button "clearButton" of window "MacGPSBabel" to true + set the title of button "selectButton" of window "MacGPSBabel" to "Add File" + end if +end selectFile +-- add another file +on addFile() + -- Choose a file (using the open file dialog box) + set aFile to choose file with prompt "Select another input file" + set contents of text field "inputFile" of window "MacGPSBabel" to aFile + set the contents of popup button "inPop" of window "MacGPSBabel" to 0 +end addFile + +-- SCRIPTS FOR CONTROLLING THE CONVERSION +-- work out which kind of conversion to do +on sendFile(fileList) + -- check for options selected + if state of button "GPSswitchIN" of window "MacGPSBabel" = 1 then + my GPSSend() + return 0 + else if state of button "GPSswitchOUT" of window "MacGPSBabel" = 1 then + set visible of window "SelectGPS" to true + set state of button "trackSwitch" of window "SelectGPS" to 0 + set enabled of button "trackSwitch" of window "SelectGPS" to false + return 0 + else if the title of current menu item of popup button "inPop" of window "MacGPSBabel" = "Select Input File Type" then + display dialog "Please select an input file type" buttons {"OK"} default button 1 + return 0 + else if the title of current menu item of popup button "outPop" of window "MacGPSBabel" = "Select Output File Type" then + display dialog "Please select an output file type" buttons {"OK"} default button 1 + return 0 + end if + + -- select where to save the file + my convertFile(fileList) +end sendFile + +-- this script handles conversions between file types +on convertFile(fileList) + -- create string for filters + if visible of window "filterWindow" is true then + set filterText to my applyFilters() + else + set filterText to "" + end if + + -- create string for input files + set fileText to "" + repeat with theItem in fileList + set currentInIndex to item 2 of theItem + set inType to item (currentInIndex) of typeList + set inputFile to quoted form of item 1 of theItem + set fileText to fileText & " -i " & inType & " -f " & inputFile + end repeat + + -- create strings for output file + set currentOutIndex to contents of popup button "outPop" of window "MacGPSBabel" + set outType to item (currentOutIndex) of typeList + if visible of window "filterWindow" is true then + if state of button "smartSwitch" of window "filterWindow" is equal to 1 then + set smartSwitch to " -s" + if contents of text field "smartLen" of window "filterWindow" is not equal to "" then + set outType to outType & ",snlen=" & ((contents of text field "smartLen" of window "filterWindow") as integer) & " " + end if + else + set smartSwitch to "" + end if + else + set smartSwitch to "" + end if + set OutExt to item (currentOutIndex) of extList + -- set outPath to directory of aFile + tell save panel + set title to "Save Output As" + set prompt to "Save" + set treat packages as directories to 0 + end tell + set oldDelimiters to AppleScript's text item delimiters + set AppleScript's text item delimiters to "/" + set TempFileName to last text item of inputFile + set AppleScript's text item delimiters to "." + set TempFileName to the first text item of TempFileName + set AppleScript's text item delimiters to oldDelimiters + if OutExt is not equal to "" then + set TempFileName to TempFileName & "." & OutExt + end if + set theResult to display save panel in directory aFile with file name TempFileName + if theResult is 1 then + set outputFile to (path name of save panel) as string + else + set outputFile to "" + display dialog "conversion cancelled" buttons {"OK"} default button 1 + return 0 + end if + -- do the script + set thePath to POSIX path of (path to me) as string + set theConvertScript to (quoted form of thePath & "Contents/Resources/gpsbabel" & smartSwitch & fileText & " " & filterText & "-o " & outType & " -F " & quoted form of outputFile) as string + if (my runBabel(theConvertScript)) then + display dialog "File conversion is complete" buttons {"OK"} default button 1 + else + display dialog "Sorry, the file conversion failed" buttons {"OK"} default button 1 + end if + my clearFiles() +end convertFile + +-- GPS RECEIVER HANDLERS +-- open the GPS receiver window +on GPSSend() + if the title of current menu item of popup button "outPop" of window "MacGPSBabel" = "Select Output File Type" then + display dialog "Please select an output file type" buttons {"OK"} default button 1 + else + set visible of window "SelectGPS" to true + set enabled of button "trackSwitch" of window "selectGPS" to true + end if +end GPSSend +-- deal with uploading files to GPS receiver +on uploadFile(fileList) + -- create string for filters + if visible of window "filterWindow" is true then + set filterText to my applyFilters() + else + set filterText to "" + end if + + -- create string for input files + set fileText to "" + repeat with theItem in fileList + set currentInIndex to item 2 of theItem + set inType to item (currentInIndex) of typeList + set inputFile to quoted form of item 1 of theItem + set fileText to fileText & " -i " & inType & " -f " & inputFile + end repeat + + -- create string for GPS unit + if the title of popup button "gpsPop" of window "selectGPS" is equal to "Garmin" then + set gpsText to " garmin " + else + set gpsText to " magellan " + end if + if visible of window "filterWindow" is true then + if state of button "smartSwitch" of window "filterWindow" is equal to 1 then + set smartSwitch to " -s" + if contents of text field "smartLen" of window "filterWindow" is not equal to "" then + set gpsText to gpsText & ",snlen=" & ((contents of text field "smartLen" of window "filterWindow") as integer) & " " + end if + else + set smartSwitch to "" + end if + else + set smartSwitch to "" + end if + + -- run the script + set thePath to POSIX path of (path to me) as string + set visible of window "SelectGPS" to false + set visible of window "MacGPSBabel" to true + set serialText to "-F /dev/cu." & (the title of popup button "serialPop" of window "selectGPS") + set theConvertScript to (quoted form of thePath & "Contents/Resources/gpsbabel" & smartSwitch & fileText & " " & filterText & "-o " & gpsText & serialText) + if (my runBabel(theConvertScript)) then + display dialog "Upload to" & gpsText & "GPS receiver is complete" buttons {"OK"} default button 1 + else + display dialog "Sorry, upload to" & gpsText & "GPS receiver failed" buttons {"OK"} default button 1 + end if +end uploadFile +-- deal with downloading files from GPS receiver +on downloadFile() + set outName to "Waypoints." + if visible of window "filterWindow" is true then + set filterText to my applyFilters() + else + set filterText to "" + end if + if state of button "trackSwitch" of window "selectGPS" is equal to 1 then + set trackText to " -t" + set outName to "Tracks." + else + set trackText to "" + end if + set thePath to POSIX path of (path to me) as string + + tell save panel + set title to "Save Output As" + set prompt to "Save" + set treat packages as directories to 0 + end tell + + set currentOutIndex to contents of popup button "outPop" of window "MacGPSBabel" + set outType to item (currentOutIndex) of typeList + if visible of window "filterWindow" is true then + if state of button "smartSwitch" of window "filterWindow" is equal to 1 then + set smartSwitch to " -s" + if contents of text field "smartLen" of window "filterWindow" is not equal to "" then + set outType to outType & ",snlen=" & ((contents of text field "smartLen" of window "filterWindow") as integer) & " " + end if + else + set smartSwitch to "" + end if + else + set smartSwitch to "" + end if + set OutExt to item (currentOutIndex) of extList + set TempFileName to outName & OutExt + set theResult to display save panel in directory "~/Desktop" with file name TempFileName + if theResult is 1 then + set outputFile to (path name of save panel) as string + if the title of popup button "gpsPop" of window "selectGPS" is equal to "Garmin" then + set gpsText to " garmin " + else + set gpsText to " magellan " + end if + set serialText to "/dev/cu." & (the title of popup button "serialPop" of window "selectGPS") + set visible of window "SelectGPS" to false + set visible of window "MacGPSBabel" to true + set theConvertScript to (quoted form of thePath & "Contents/Resources/gpsbabel" & smartSwitch & trackText & " -i" & gpsText & "-f " & serialText & " " & filterText & " -o " & outType & " -F " & quoted form of outputFile) + if (my runBabel(theConvertScript)) then + display dialog "Download from" & gpsText & "GPS receiver is complete" buttons {"OK"} default button 1 + else + display dialog "Sorry, download from" & gpsText & "GPS receiver failed" buttons {"OK"} default button 1 + end if + else + set outputFile to "" + end if +end downloadFile + +-- Send the call to gpsbabel +on runBabel(theConvertScript) + log "Tried to execute: " & theConvertScript + set theConvertScript to theConvertScript & " 2>&1" + feedbackBusy(true) + try + set scriptOut to do shell script theConvertScript as string + set babelHappy to true + log "Success! gpsbabel returned: " & scriptOut + on error + set scriptOut to "gpsbabel encountered an error" + set babelHappy to false + log "Error! gpsbabel returned: " & scriptOut + end try + feedbackBusy(false) + if visible of window "debugWindow" is true then + set the contents of text view 1 of scroll view 1 of window "debugWindow" to "" + set the contents of text view 1 of scroll view 1 of window "debugWindow" to "MacGPSBabel Report" & return & return & "The Shell Script:" & return & theConvertScript & return & return & convertYN & return & return & "Output From gpsbabel:" & return & scriptOut + end if + return babelHappy +end runBabel + + + + +-- FILTERING HANDLERS +-- show filters window +on showFilters() + if visible of window "filterWindow" is false then + set visible of window "filterWindow" to true + set the title of button "filterButton" of window "MacGPSBabel" to "Remove Filters" + else + set visible of window "filterWindow" to false + set the title of button "filterButton" of window "MacGPSBabel" to "Setup Filters" + end if +end showFilters +-- create the filter code +on applyFilters() + set filterText to "" + if state of button "distanceFilter" of window "filterWindow" is equal to 1 then + set distanceText to "-x position" + if contents of text field "dist1" of window "filterWindow" is not equal to "" then + set distanceText to distanceText & ",distance=" & (contents of text field "dist1" of window "filterWindow") + if title of popup button "dist1Select" of window "filterWindow" is equal to "Feet" then + set distanceText to distanceText & "f " + else + set distanceText to distanceText & "m " + end if + end if + else + set distanceText to "" + end if + if state of button "radiusFilter" of window "filterWindow" is equal to 1 then + set radiusText to "-x radius" + if contents of text field "dist2" of window "filterWindow" is not equal to "" then + set radiusText to radiusText & ",distance=" & (contents of text field "dist2" of window "filterWindow") + if title of popup button "dist2Select" of window "filterWindow" is equal to "Miles" then + set radiusText to radiusText & "M" + else + set radiusText to radiusText & "K" + end if + if the title of current menu item of popup button "nsSelect" of window "filterWindow" = "N" then + set lat to 1 + else + set lat to -1 + end if + if the title of current menu item of popup button "ewSelect" of window "filterWindow" = "W" then + set lon to -1 + else + set lon to 1 + end if + set latDeg to lat * (((the contents of text field "nDeg" of window "filterWindow") as number) + (((the contents of text field "nMin" of window "filterWindow") as number) / 60)) as string + set lonDeg to lon * ((the contents of text field "wDeg" of window "filterWindow") + ((the contents of text field "wMin" of window "filterWindow") / 60)) as string + set radiusText to radiusText & ",lat=" & latDeg & ",lon=" & lonDeg & " " + end if + else + set radiusText to "" + end if + if state of button "locationFilter" of window "filterWindow" is equal to 1 then + set duplicateText to "-x duplicate,location" + if state of button "shortFilter" of window "filterWindow" is not equal to 1 then + set duplicateText to duplicateText & " " + end if + else + set duplicateText to "" + end if + if state of button "shortFilter" of window "filterWindow" is equal to 1 then + if duplicateText is not equal to "" then + set duplicateText to duplicateText & ",shortname " + else + set duplicateText to "-x duplicate,shortname " + end if + end if + if state of button "arcSwitch" of window "filterWindow" is equal to 1 then + if (contents of text field "arcDist" of window "filterWindow" is not equal to "") then + if title of popup button "arcUnits" of window "filterWindow" is equal to "Miles" then + set aUnit to "M" + else + set aUnit to "K" + end if + set arcDistance to (contents of text field "arcDist" of window "filterWindow") & aUnit + set arcText to "-x arc,file=\"" & (contents of text field "arcFile" of window "filterWindow") & "\",distance=" & arcDistance & " " + else + display dialog "Please input a distance for the arc filter" buttons ["OK"] default button 1 + set arcText to "" + break + end if + else + set arcText to "" + end if + if state of button "polySwitch" of window "filterWindow" is equal to 1 then + set polyText to "-x polygon,file=\"" & (contents of text field "arcFile" of window "filterWindow") & "\" " + else + set polyText to "" + end if + set filterText to distanceText & radiusText & duplicateText & arcText & polyText + return filterText +end applyFilters + +-- handlers to deal with the GPS receiver checkboxes +on GPSSwitchIN() + if state of button "GPSswitchIN" of window "MacGPSBabel" = 1 then + set enabled of button "selectButton" of window "MacGPSBabel" to false + set enabled of button "clearButton" of window "MacGPSBabel" to false + set enabled of button "sendButton" of window "MacGPSBabel" to true + set contents of text field "inputFile" of window "MacGPSBabel" to "" + set enabled of text field "inputFile" of window "MacGPSBabel" to false + set enabled of popup button "inPop" of window "MacGPSBabel" to false + set title of button "sendButton" of window "MacGPSBabel" to "Download..." + else + set enabled of button "selectButton" of window "MacGPSBabel" to true + set enabled of button "sendButton" of window "MacGPSBabel" to false + set enabled of text field "inputFile" of window "MacGPSBabel" to true + set enabled of popup button "inPop" of window "MacGPSBabel" to true + end if + if state of button "GPSswitchIN" of window "MacGPSBabel" = 0 and state of button "GPSswitchOUT" of window "MacGPSBabel" = 0 then + set title of button "sendButton" of window "MacGPSBabel" to "Convert" + end if +end GPSSwitchIN +on GPSswitchOUT() + if state of button "GPSswitchOUT" of window "MacGPSBabel" = 1 then + set enabled of popup button "outPop" of window "MacGPSBabel" to false + set title of button "sendButton" of window "MacGPSBabel" to "Upload..." + else + set enabled of popup button "outPop" of window "MacGPSBabel" to true + end if + if state of button "GPSswitchIN" of window "MacGPSBabel" = 0 and state of button "GPSswitchOUT" of window "MacGPSBabel" = 0 then + set title of button "sendButton" of window "MacGPSBabel" to "Convert" + end if +end GPSswitchOUT + +-- start/stop the Main window's progress indicator +on feedbackBusy(yn) + tell window "MacGPSBabel" + if yn then + start progress indicator 1 + else + stop progress indicator 1 + end if + end tell +end feedbackBusy + +on clearFiles() + set contents of text field "inputFile" of window "MacGPSBabel" to "" + set fileList to {} + set title of button "selectButton" of window "MacGPSBabel" to "Select File" + set enabled of button "sendButton" of window "MacGPSBabel" to false + set key equivalent of button "selectButton" of window "MacGPSBabel" to return + set enabled of button "clearButton" of window "MacGPSBabel" to false + + -- reset controls to user defaults + -- read current user defaults and set window controls as needed + my readSettings() + + -- deal with changes to MacGPSBabel window needed if any of the GPS check boxes are checked by default + if state of button "GPSswitchIN" of window "MacGPSBabel" is equal to 1 then + my gpsIN() + end if + if state of button "GPSswitchOUT" of window "MacGPSBabel" is equal to 1 then + my gpsOUT() + end if +end clearFiles + + +-- read user defaults +on readSettings() + tell user defaults + set defaultInputIndex to contents of default entry "theInputType" as integer + set defaultOutputIndex to contents of default entry "theOutputType" as integer + set defaultgpsIN to contents of default entry "gpsIN" as boolean + set defaultgpsOUT to contents of default entry "gpsOUT" as boolean + end tell + -- call method "setObjectValue:" of object (popup button "inPop" of window "MacGPSBabel") with parameter defaultInputIndex + -- call method "synchronizeTitleAndSelectedItem" of object (popup button "inPop" of window "MacGPSBabel") + set contents of popup button "inPop" of window "MacGPSBabel" to defaultInputIndex + set contents of popup button "outPop" of window "MacGPSBabel" to defaultOutputIndex + set state of button "GPSswitchIN" of window "MacGPSBabel" to defaultgpsIN + set state of button "GPSswitchOUT" of window "MacGPSBabel" to defaultgpsOUT +end readSettings + +-- scripts for dealing with GPS checkboxes on MacGPSBabel window +on gpsIN() + if state of button "GPSswitchIN" of window "MacGPSBabel" = 1 then + set enabled of button "selectButton" of window "MacGPSBabel" to false + set enabled of button "clearButton" of window "MacGPSBabel" to false + set enabled of button "sendButton" of window "MacGPSBabel" to true + set contents of text field "inputFile" of window "MacGPSBabel" to "" + set enabled of text field "inputFile" of window "MacGPSBabel" to false + set enabled of popup button "inPop" of window "MacGPSBabel" to false + else + set enabled of button "selectButton" of window "MacGPSBabel" to true + set enabled of button "sendButton" of window "MacGPSBabel" to false + set enabled of text field "inputFile" of window "MacGPSBabel" to true + set enabled of popup button "inPop" of window "MacGPSBabel" to true + end if +end gpsIN +on gpsOUT() + if state of button "GPSswitchOUT" of window "MacGPSBabel" = 1 then + set enabled of popup button "outPop" of window "MacGPSBabel" to false + else + set enabled of popup button "outPop" of window "MacGPSBabel" to true + end if +end gpsOUT + +-- List Populating Handlers + +-- find the serial ports +on getSerial() + set myList to {} + set theScript to "cd /dev; ls | grep cu\\." + set scriptOut to (do shell script theScript) as string + set theCount to count of paragraphs in scriptOut + set i to 0 + set defaultDelimiters to AppleScript's text item delimiters + set AppleScript's text item delimiters to {"."} + repeat until i = theCount + set i to i + 1 + set theWords to the count of text items in paragraph i of scriptOut + set z to 2 + set the end of myList to (text items z thru theWords of paragraph i of scriptOut) as string + end repeat + set AppleScript's text item delimiters to defaultDelimiters + return myList +end getSerial + +-- handler (called at startup) to check with GPS Babel which file formats it can handle. Return the result as a list +on getFormats() + set myList to {} + set typeList to {} + set extList to {} + set thePath to POSIX path of (path to me) as string + set scriptOut to (do shell script quoted form of thePath & "Contents/Resources/gpsbabel -^1") as string + set theCount to count of paragraphs in scriptOut + set defaultDelimiters to AppleScript's text item delimiters + set AppleScript's text item delimiters to tab + repeat with i from 1 to theCount + set theLine to paragraph i of scriptOut + if (first text item of theLine) is equal to "file" then + set the end of typeList to the second text item of theLine + set the end of extList to the third text item of theLine + set the end of myList to the last text item of theLine + end if + end repeat + set AppleScript's text item delimiters to defaultDelimiters + return myList +end getFormats \ No newline at end of file diff --git a/macgpsbabel/MacGPSBabel.pbproj/default.pbxuser b/macgpsbabel/MacGPSBabel.pbproj/default.pbxuser new file mode 100644 index 000000000..b9c3ff46f --- /dev/null +++ b/macgpsbabel/MacGPSBabel.pbproj/default.pbxuser @@ -0,0 +1,26 @@ +// !$*UTF8*$! +{ + 29B97326FDCFA39411CA2CEA = { + activeExec = 0; + targetExecs = { + macosx = ( + DA206CF0015C4D9F03C91932, + ); + }; + }; + DA206CF0015C4D9F03C91932 = { + activeArgIndex = 2147483647; + argumentStrings = ( + ); + debuggerPlugin = ASKDebugger; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + isa = PBXExecutable; + shlibInfoDictList = ( + ); + sourceDirectories = ( + ); + }; +} diff --git a/macgpsbabel/MacGPSBabel.pbproj/jeremya.pbxuser b/macgpsbabel/MacGPSBabel.pbproj/jeremya.pbxuser new file mode 100644 index 000000000..3964792fb --- /dev/null +++ b/macgpsbabel/MacGPSBabel.pbproj/jeremya.pbxuser @@ -0,0 +1,1034 @@ +// !$*UTF8*$! +{ + 089C165DFE840E0CC02AAC07 = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {711, 428}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRect = "{{0, 0}, {711, 428}}"; + sepNavWindowFrame = "{{19, 183}, {750, 558}}"; + }; + }; + 29B97313FDCFA39411CA2CEA = { + activeBuildStyle = 4A9504CCFFE6A4B311CA0CBA; + activeExecutable = DA206CF0015C4D9F03C91932; + activeTarget = 29B97326FDCFA39411CA2CEA; + addToTargets = ( + 29B97326FDCFA39411CA2CEA, + ); + breakpoints = ( + ); + codeSenseManager = 3F8AAF0906E7E5D400E74F19; + executables = ( + DA206CF0015C4D9F03C91932, + ); + perUserDictionary = { + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 604, + 20, + 108, + 43, + 43, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + PBXFileDataSource_Target_ColumnID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXSymbolsDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXSymbolsDataSource_SymbolNameID; + PBXFileTableDataSourceColumnWidthsKey = ( + 16, + 132.8008, + 161.0356, + 138.2085, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXSymbolsDataSource_SymbolTypeIconID, + PBXSymbolsDataSource_SymbolNameID, + PBXSymbolsDataSource_SymbolTypeID, + PBXSymbolsDataSource_ReferenceNameID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.XCSCMDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 20, + 226, + 20, + 40, + 43, + 43, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_SCM_ColumnID, + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + PBXFileDataSource_Target_ColumnID, + ); + }; + PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 210, + 50, + 20, + 50, + 43, + 43, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXTargetDataSource_PrimaryAttribute, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + ); + }; + PBXPerProjectTemplateStateSaveDate = 116907658; + PBXPrepackagedSmartGroups_v2 = ( + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + activationKey = OldTargetSmartGroup; + clz = PBXTargetSmartGroup; + description = "Displays all targets of the project."; + globalID = 1C37FABC04509CD000000102; + name = Targets; + preferences = { + image = Targets; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXTargetSmartGroup2; + description = "Displays all targets of the project as well as nested build phases."; + globalID = 1C37FBAC04509CD000000102; + name = Targets; + preferences = { + image = Targets; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXExecutablesSmartGroup; + description = "Displays all executables of the project."; + globalID = 1C37FAAC04509CD000000102; + name = Executables; + preferences = { + image = Executable; + }; + }, + { + " PBXTransientLocationAtTop " = bottom; + absolutePathToBundle = ""; + clz = PBXErrorsWarningsSmartGroup; + description = "Displays files with errors or warnings."; + globalID = 1C08E77C0454961000C914BD; + name = "Errors and Warnings"; + preferences = { + fnmatch = ""; + image = WarningsErrors; + recursive = 1; + regex = ""; + root = ""; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXFilenameSmartGroup; + description = "Filters items in a given group (potentially recursively) based on matching the name with the regular expression of the filter."; + globalID = 1CC0EA4004350EF90044410B; + name = "Implementation Files"; + preferences = { + canSave = 1; + fnmatch = ""; + image = SmartFolder; + isLeaf = 0; + recursive = 1; + regex = "?*\\.[mcMC]"; + root = ""; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXFilenameSmartGroup; + description = "This group displays Interface Builder NIB Files."; + globalID = 1CC0EA4004350EF90041110B; + name = "NIB Files"; + preferences = { + canSave = 1; + fnmatch = "*.nib"; + image = SmartFolder; + isLeaf = 0; + recursive = 1; + regex = ""; + root = ""; + }; + }, + { + PBXTransientLocationAtTop = no; + absolutePathToBundle = ""; + clz = PBXFindSmartGroup; + description = "Displays Find Results."; + globalID = 1C37FABC05509CD000000102; + name = "Find Results"; + preferences = { + image = spyglass; + }; + }, + { + PBXTransientLocationAtTop = no; + absolutePathToBundle = ""; + clz = PBXBookmarksSmartGroup; + description = "Displays Project Bookmarks."; + globalID = 1C37FABC05539CD112110102; + name = Bookmarks; + preferences = { + image = Bookmarks; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = XCSCMSmartGroup; + description = "Displays files with interesting SCM status."; + globalID = E2644B35053B69B200211256; + name = SCM; + preferences = { + image = PBXRepository; + isLeaf = 0; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXSymbolsSmartGroup; + description = "Displays all symbols for the project."; + globalID = 1C37FABC04509CD000100104; + name = "Project Symbols"; + preferences = { + image = ProjectSymbols; + isLeaf = 1; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXFilenameSmartGroup; + description = "Filters items in a given group (potentially recursively) based on matching the name with the regular expression of the filter."; + globalID = PBXTemplateMarker; + name = "Simple Filter SmartGroup"; + preferences = { + canSave = 1; + fnmatch = "*.nib"; + image = SmartFolder; + isLeaf = 0; + recursive = 1; + regex = ""; + root = ""; + }; + }, + { + PBXTransientLocationAtTop = bottom; + absolutePathToBundle = ""; + clz = PBXFilenameSmartGroup; + description = "Filters items in a given group (potentially recursively) based on matching the name with the regular expression of the filter."; + globalID = PBXTemplateMarker; + name = "Simple Regular Expression SmartGroup"; + preferences = { + canSave = 1; + fnmatch = ""; + image = SmartFolder; + isLeaf = 0; + recursive = 1; + regex = "?*\\.[mcMC]"; + root = ""; + }; + }, + { + PBXTransientLocationAtTop = bottom; + clz = XDDesignSmartGroup; + description = "Displays Xdesign models"; + globalID = 2E4A936305E6979E00701470; + name = Design; + preferences = { + image = Design; + isLeaf = 0; + }; + }, + ); + PBXWorkspaceContents = ( + { + LeftSlideOut = { + Split0 = { + Split0 = { + NavContent0 = { + bookmark = 3F89A6FF06D5B1F6007C6F9A; + history = ( + F5E2D67E05CDA550017C67C1, + F5E2D67F05CDA550017C67C1, + F5E2D68005CDA550017C67C1, + F5EAB15305FF78D401A80065, + 3F7037A606B335A800A80064, + 3F7037A706B335A800A80064, + 3F89A6F906D5B1F6007C6F9A, + 3F89A6FA06D5B1F6007C6F9A, + 3F89A6FB06D5B1F6007C6F9A, + ); + prevStack = ( + F5F16EF80527D1B401A80064, + F54D1E350548BAC0017C67C1, + F54D1E360548BAC0017C67C1, + F54D1E370548BAC0017C67C1, + F52E6CB905995A8001A80064, + F52E6CBA05995A8001A80064, + F52E6CBB05995A8001A80064, + F52E6CBC05995A8001A80064, + F52E6CBD05995A8001A80064, + F52E6CBE05995A8001A80064, + F508F40305A7AE8A01A80064, + F508F40405A7AE8A01A80064, + F508F40505A7AE8A01A80064, + F52B871705A8A05001A80064, + F52B871905A8A05001A80064, + F52B871B05A8A05001A80064, + F554DF6805AE715801A80064, + F554DF6905AE715801A80064, + F554DF6A05AE715801A80064, + F554DF6B05AE715801A80064, + F51CF6B405AF9E8901A80064, + F51C069F05C4C5B4017C67C1, + F51C06A005C4C5B4017C67C1, + F51C06A105C4C5B4017C67C1, + F557060805C8B0C0017C67C1, + F557060905C8B0C0017C67C1, + F557060A05C8B0C0017C67C1, + F557060B05C8B0C0017C67C1, + F557060C05C8B0C0017C67C1, + F50EB4AF05CB231C017C67C1, + F523D7AD05CB3DB9017C67C1, + F523D7AE05CB3DB9017C67C1, + F586ED0705CC1ED5017C67C1, + F586ED0805CC1ED5017C67C1, + F586ED0905CC1ED5017C67C1, + F586ED0A05CC1ED5017C67C1, + F586ED0B05CC1ED5017C67C1, + F586ED0C05CC1ED5017C67C1, + F586ED0D05CC1ED5017C67C1, + F586ED0E05CC1ED5017C67C1, + F586ED0F05CC1ED5017C67C1, + F586ED1005CC1ED5017C67C1, + F586ED1105CC1ED5017C67C1, + F586ED1205CC1ED5017C67C1, + F586ED1305CC1ED5017C67C1, + F586ED1405CC1ED5017C67C1, + F5CCE1EA05CCCE05017C67C1, + F5CCE1EB05CCCE05017C67C1, + F5E2D68205CDA550017C67C1, + F5E2D68305CDA550017C67C1, + F5E2D68405CDA550017C67C1, + F5E2D68505CDA550017C67C1, + F5E2D68605CDA550017C67C1, + F58F331C05CF5079017C67C1, + F58F331D05CF5079017C67C1, + F58F331E05CF5079017C67C1, + F58F331F05CF5079017C67C1, + F58F332005CF5079017C67C1, + F58F332105CF5079017C67C1, + F58F332205CF5079017C67C1, + F58F332305CF5079017C67C1, + F58F332405CF5079017C67C1, + F58F332505CF5079017C67C1, + F5D9F70F05CF63CD017C67C1, + F5DC7AAE05D47E10017C67C1, + F5DC7AB305D49339017C67C1, + F5DC7AB405D49339017C67C1, + F5DC7AB805D495EE017C67C1, + F588B18805DF3294017C67C1, + F5E67E8505DFEBAB017C67C1, + F5E67E8605DFEBAB017C67C1, + F5516AA205E1AD5A017C67C1, + F5516AA305E1AD5A017C67C1, + F5516AA405E1AD5A017C67C1, + F5516AA505E1AD5A017C67C1, + F5516AA605E1AD5A017C67C1, + F5516AA705E1AD5A017C67C1, + F5516AA805E1AD5A017C67C1, + F5516AA905E1AD5A017C67C1, + F5516AAA05E1AD5A017C67C1, + F5516AAB05E1AD5A017C67C1, + F5516AAC05E1AD5A017C67C1, + F5F2761005EDB91901A80065, + F5F411C805EEF803017C67C1, + F5EAB15505FF78D401A80065, + F5EAB15605FF78D401A80065, + F505F8000617AE8001A80065, + F505F8010617AE8001A80065, + F505F8020617AE8001A80065, + F53C482A061A912901A80065, + F53C482B061A912901A80065, + 3F0A602B062B681C007C67C1, + 3F0A602C062B681C007C67C1, + 3F0A602D062B681C007C67C1, + 3F579AB40645EEDF007C6F93, + 3F579AB50645EEDF007C6F93, + 3FB94844069C744B00A80064, + 3FB94845069C744B00A80064, + 3FB94846069C744B00A80064, + 3FB94847069C744B00A80064, + 3FB94848069C744B00A80064, + 3FB94849069C744B00A80064, + 3F9319E906AF4FA500A80064, + 3F9319EA06AF4FA500A80064, + 3F9319EB06AF4FA500A80064, + 3F0BDAD706AF6C1F00A80064, + 3F7037A806B335A800A80064, + 3F7037A906B335A800A80064, + 3F7037AA06B335A800A80064, + 3F7037AB06B335A800A80064, + 3F2FDB0806B4943500A80064, + 3F5F093C06B4953400A80064, + 3F10FD0806CC4D6D00A80064, + 3F10FD0906CC4D6D00A80064, + 3F10FD0A06CC4D6D00A80064, + 3F10FD0B06CC4D6D00A80064, + 3F10FD0C06CC4D6D00A80064, + 3FC9F73A06CEA744007C6F9A, + 3F89A6FC06D5B1F6007C6F9A, + 3F89A6FD06D5B1F6007C6F9A, + 3F89A6FE06D5B1F6007C6F9A, + ); + }; + NavCount = 1; + NavGeometry0 = { + Frame = "{{0, 0}, {864, 661}}"; + NavBarVisible = YES; + }; + NavSplitVertical = NO; + }; + SplitCount = 1; + Tab1 = { + Debugger = { + Split0 = { + SplitCount = 2; + }; + SplitCount = 1; + TabCount = 2; + }; + LauncherConfigVersion = 7; + }; + Tab2 = { + LauncherConfigVersion = 3; + Runner = { + }; + }; + TabCount = 5; + }; + SplitCount = 1; + Tab1 = { + OptionsSetName = "Hierarchy, all classes"; + }; + TabCount = 5; + }; + }, + { + LeftSlideOut = { + Split0 = { + Split0 = { + NavCount = 1; + NavGeometry0 = { + Frame = "{{0, 0}, {685, 150}}"; + NavBarVisible = YES; + }; + NavSplitVertical = NO; + }; + SplitCount = 1; + Tab1 = { + Debugger = { + Split0 = { + SplitCount = 2; + }; + SplitCount = 1; + TabCount = 2; + }; + LauncherConfigVersion = 7; + }; + Tab2 = { + LauncherConfigVersion = 3; + Runner = { + }; + }; + TabCount = 5; + }; + SplitCount = 1; + Tab1 = { + OptionsSetName = "Hierarchy, all classes"; + }; + TabCount = 5; + }; + }, + { + LeftSlideOut = { + Split0 = { + Split0 = { + NavCount = 1; + NavGeometry0 = { + Frame = "{{0, 0}, {594, 150}}"; + NavBarVisible = YES; + }; + NavSplitVertical = NO; + }; + SplitCount = 1; + Tab1 = { + Debugger = { + Split0 = { + SplitCount = 2; + }; + SplitCount = 1; + TabCount = 2; + }; + LauncherConfigVersion = 7; + }; + Tab2 = { + LauncherConfigVersion = 3; + Runner = { + }; + }; + TabCount = 5; + }; + SplitCount = 1; + Tab1 = { + OptionsSetName = "Hierarchy, all classes"; + }; + TabCount = 5; + }; + }, + ); + PBXWorkspaceGeometries = ( + { + ContentSize = "{1148, 684}"; + LeftSlideOut = { + ActiveTab = 0; + ActiveTabName = PBXGroupTreeModule; + Collapsed = NO; + Frame = "{{0, 23}, {1148, 661}}"; + Split0 = { + Collapsed = NO; + Frame = "{{284, 0}, {864, 661}}"; + Split0 = { + Frame = "{{0, 0}, {864, 661}}"; + }; + SplitCount = 1; + Tab0 = { + Frame = "{{0, 0}, {681, 289}}"; + }; + Tab1 = { + Debugger = { + Collapsed = NO; + Frame = "{{0, 0}, {681, 150}}"; + Split0 = { + Frame = "{{0, 24}, {681, 126}}"; + Split0 = { + Frame = "{{0, 0}, {333, 126}}"; + }; + Split1 = { + DebugVariablesTableConfiguration = ( + Name, + 123, + Value, + 85, + Summary, + 105.123, + ); + Frame = "{{342, 0}, {339, 126}}"; + }; + SplitCount = 2; + }; + SplitCount = 1; + Tab0 = { + Frame = "{{0, 0}, {100, 50}}"; + }; + Tab1 = { + Frame = "{{0, 0}, {100, 50}}"; + }; + TabCount = 2; + TabsVisible = YES; + }; + Frame = "{{0, 0}, {681, 120}}"; + LauncherConfigVersion = 7; + }; + Tab2 = { + Frame = "{{0, 0}, {681, 234}}"; + LauncherConfigVersion = 3; + Runner = { + Frame = "{{0, 0}, {681, 234}}"; + }; + }; + Tab3 = { + BuildMessageFrame = "{{0, 0}, {683, 205}}"; + BuildTranscriptFrame = "{{0, 214}, {683, 2}}"; + BuildTranscriptFrameExpanded = YES; + Frame = "{{0, 0}, {681, 238}}"; + }; + Tab4 = { + Frame = "{{0, 0}, {612, 295}}"; + }; + TabCount = 5; + TabsVisible = NO; + }; + SplitCount = 1; + Tab0 = { + Frame = "{{0, 0}, {260, 661}}"; + GroupTreeTableConfiguration = ( + SCMStatusColumn, + 22, + TargetStatusColumn, + 18, + MainColumn, + 205, + ); + }; + Tab1 = { + ClassesFrame = "{{0, 0}, {250, 333}}"; + ClassesTreeTableConfiguration = ( + PBXBookColumnIdentifier, + 20, + PBXClassColumnIdentifier, + 207, + ); + Frame = "{{0, 0}, {248, 554}}"; + MembersFrame = "{{0, 342}, {250, 212}}"; + MembersTreeTableConfiguration = ( + PBXBookColumnIdentifier, + 20, + PBXMethodColumnIdentifier, + 206, + ); + }; + Tab2 = { + Frame = "{{0, 0}, {217, 554}}"; + }; + Tab3 = { + Frame = "{{0, 0}, {239, 661}}"; + TargetTableConfiguration = ( + ActiveObject, + 16, + ObjectNames, + 206.296, + ); + }; + Tab4 = { + BreakpointsTreeTableConfiguration = ( + breakpointColumn, + 197, + enabledColumn, + 31, + ); + Frame = "{{0, 0}, {250, 661}}"; + }; + TabCount = 5; + TabsVisible = YES; + }; + NavBarShownByDefault = YES; + StatusViewVisible = YES; + Template = 64ABBB4501FA494900185B06; + ToolbarVisible = YES; + WindowLocation = "{3, 0}"; + }, + { + ContentSize = "{685, 434}"; + LeftSlideOut = { + Collapsed = NO; + Frame = "{{0, 23}, {685, 411}}"; + Split0 = { + ActiveTab = 2; + ActiveTabName = PBXBuildResultsModule; + Collapsed = NO; + Frame = "{{0, 0}, {685, 411}}"; + Split0 = { + Frame = "{{0, 301}, {685, 110}}"; + }; + SplitCount = 1; + Tab0 = { + Frame = "{{0, 0}, {952, 321}}"; + }; + Tab1 = { + Debugger = { + Collapsed = NO; + Frame = "{{0, 0}, {781, 452}}"; + Split0 = { + Frame = "{{0, 24}, {781, 428}}"; + Split0 = { + Frame = "{{0, 0}, {383, 428}}"; + }; + Split1 = { + DebugVariablesTableConfiguration = ( + Name, + 123, + Value, + 85, + Summary, + 155.123, + ); + Frame = "{{392, 0}, {389, 428}}"; + }; + SplitCount = 2; + }; + SplitCount = 1; + Tab0 = { + Frame = "{{0, 0}, {100, 50}}"; + }; + Tab1 = { + Frame = "{{0, 0}, {100, 50}}"; + }; + TabCount = 2; + TabsVisible = YES; + }; + Frame = "{{0, 0}, {781, 452}}"; + LauncherConfigVersion = 7; + }; + Tab2 = { + Frame = "{{0, 0}, {685, 215}}"; + LauncherConfigVersion = 3; + Runner = { + Frame = "{{0, 0}, {685, 215}}"; + }; + }; + Tab3 = { + BuildMessageFrame = "{{0, 0}, {687, 262}}"; + BuildTranscriptFrame = "{{0, 271}, {687, 2}}"; + BuildTranscriptFrameExpanded = YES; + Frame = "{{0, 0}, {685, 295}}"; + }; + Tab4 = { + Frame = "{{0, 0}, {612, 295}}"; + }; + TabCount = 5; + TabsVisible = NO; + }; + SplitCount = 1; + Tab0 = { + Frame = "{{0, 0}, {300, 533}}"; + GroupTreeTableConfiguration = ( + TargetStatusColumn, + 18, + MainColumn, + 267, + ); + }; + Tab1 = { + ClassesFrame = "{{0, 0}, {280, 398}}"; + ClassesTreeTableConfiguration = ( + PBXBookColumnIdentifier, + 20, + PBXClassColumnIdentifier, + 237, + ); + Frame = "{{0, 0}, {278, 659}}"; + MembersFrame = "{{0, 407}, {280, 252}}"; + MembersTreeTableConfiguration = ( + PBXBookColumnIdentifier, + 20, + PBXMethodColumnIdentifier, + 236, + ); + }; + Tab2 = { + Frame = "{{0, 0}, {200, 100}}"; + }; + Tab3 = { + Frame = "{{0, 0}, {200, 100}}"; + TargetTableConfiguration = ( + ActiveObject, + 16, + ObjectNames, + 202.296, + ); + }; + Tab4 = { + BreakpointsTreeTableConfiguration = ( + breakpointColumn, + 197, + enabledColumn, + 31, + ); + Frame = "{{0, 0}, {250, 100}}"; + }; + TabCount = 5; + TabsVisible = NO; + }; + NavBarShownByDefault = YES; + StatusViewVisible = YES; + Template = F5314676015831810DCA290F; + ToolbarVisible = YES; + WindowLocation = "{7, 250}"; + }, + { + ContentSize = "{594, 303}"; + LeftSlideOut = { + Collapsed = NO; + Frame = "{{0, 23}, {594, 280}}"; + Split0 = { + ActiveTab = 1; + ActiveTabName = PBXRunSessionModule; + Collapsed = YES; + Frame = "{{0, 0}, {594, 280}}"; + Split0 = { + Frame = "{{1e+06, 1e+06}, {594, 27}}"; + }; + SplitCount = 1; + Tab0 = { + Frame = "{{0, 0}, {804, 321}}"; + }; + Tab1 = { + Debugger = { + Collapsed = NO; + Frame = "{{0, 0}, {594, 274}}"; + Split0 = { + Frame = "{{0, 24}, {594, 250}}"; + Split0 = { + Frame = "{{0, 0}, {290, 250}}"; + }; + Split1 = { + DebugVariablesTableConfiguration = ( + Name, + 123, + Value, + 85, + Summary, + 62.123, + ); + Frame = "{{299, 0}, {295, 250}}"; + }; + SplitCount = 2; + }; + SplitCount = 1; + Tab0 = { + Frame = "{{0, 0}, {100, 50}}"; + }; + Tab1 = { + Frame = "{{0, 0}, {100, 50}}"; + }; + TabCount = 2; + TabsVisible = YES; + }; + Frame = "{{0, 0}, {594, 274}}"; + LauncherConfigVersion = 7; + }; + Tab2 = { + Frame = "{{0, 0}, {594, 274}}"; + LauncherConfigVersion = 3; + Runner = { + Frame = "{{0, 0}, {594, 274}}"; + }; + }; + Tab3 = { + BuildMessageFrame = "{{0, 0}, {614, 262}}"; + BuildTranscriptFrame = "{{0, 271}, {614, 2}}"; + BuildTranscriptFrameExpanded = YES; + Frame = "{{0, 0}, {612, 295}}"; + }; + Tab4 = { + Frame = "{{0, 0}, {612, 295}}"; + }; + TabCount = 5; + TabsVisible = NO; + }; + SplitCount = 1; + Tab0 = { + Frame = "{{0, 0}, {300, 533}}"; + GroupTreeTableConfiguration = ( + TargetStatusColumn, + 18, + MainColumn, + 267, + ); + }; + Tab1 = { + ClassesFrame = "{{0, 0}, {280, 398}}"; + ClassesTreeTableConfiguration = ( + PBXBookColumnIdentifier, + 20, + PBXClassColumnIdentifier, + 237, + ); + Frame = "{{0, 0}, {278, 659}}"; + MembersFrame = "{{0, 407}, {280, 252}}"; + MembersTreeTableConfiguration = ( + PBXBookColumnIdentifier, + 20, + PBXMethodColumnIdentifier, + 236, + ); + }; + Tab2 = { + Frame = "{{0, 0}, {200, 100}}"; + }; + Tab3 = { + Frame = "{{0, 0}, {200, 386}}"; + TargetTableConfiguration = ( + ActiveObject, + 16, + ObjectNames, + 202.296, + ); + }; + Tab4 = { + BreakpointsTreeTableConfiguration = ( + breakpointColumn, + 197, + enabledColumn, + 31, + ); + Frame = "{{0, 0}, {250, 386}}"; + }; + TabCount = 5; + TabsVisible = NO; + }; + NavBarShownByDefault = YES; + StatusViewVisible = YES; + Template = F5534CB2020F3F8A0DCA290F; + ToolbarVisible = YES; + WindowLocation = "{4, 381}"; + }, + ); + PBXWorkspaceStateSaveDate = 116907658; + }; + perUserProjectItems = { + 3F13581706F7DEF5001F6BE7 = 3F13581706F7DEF5001F6BE7; + 3F13583006F7EC6B001F6BE7 = 3F13583006F7EC6B001F6BE7; + 3FB41B8906EFB84A0017502D = 3FB41B8906EFB84A0017502D; + 3FB41B8B06EFB84A0017502D = 3FB41B8B06EFB84A0017502D; + 3FB41B8C06EFB84A0017502D = 3FB41B8C06EFB84A0017502D; + }; + sourceControlManager = 3F8AAF0806E7E5D400E74F19; + userBuildSettings = { + }; + }; + 29B97326FDCFA39411CA2CEA = { + activeExec = 0; + executables = ( + DA206CF0015C4D9F03C91932, + ); + }; + 3F13581706F7DEF5001F6BE7 = { + fRef = DA206CF3015C4E8B03C91932; + isa = PBXTextBookmark; + name = "MacGPSBabel.applescript: 815"; + rLen = 0; + rLoc = 35444; + rType = 0; + vrLen = 1617; + vrLoc = 22605; + }; + 3F13583006F7EC6B001F6BE7 = { + fRef = DA206CF3015C4E8B03C91932; + isa = PBXTextBookmark; + name = "MacGPSBabel.applescript: 839"; + rLen = 0; + rLoc = 35550; + rType = 0; + vrLen = 1415; + vrLoc = 23045; + }; + 3F8AAF0806E7E5D400E74F19 = { + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + isa = PBXSourceControlManager; + scmConfiguration = { + }; + scmType = ""; + }; + 3F8AAF0906E7E5D400E74F19 = { + indexTemplatePath = ""; + isa = PBXCodeSenseManager; + usesDefaults = 1; + wantsCodeCompletion = 1; + wantsCodeCompletionAutoSuggestions = 0; + wantsCodeCompletionCaseSensitivity = 1; + wantsCodeCompletionListAlways = 1; + wantsCodeCompletionOnlyMatchingItems = 1; + wantsCodeCompletionParametersIncluded = 1; + wantsCodeCompletionPlaceholdersInserted = 1; + wantsCodeCompletionTabCompletes = 1; + wantsIndex = 1; + }; + 3FB41B8906EFB84A0017502D = { + fRef = DA206CF4015C4E8B03C91932; + fallbackIsa = PBXBookmark; + isa = ASKDictionaryBookmark; + }; + 3FB41B8B06EFB84A0017502D = { + fRef = DA206CF3015C4E8B03C91932; + isa = PBXTextBookmark; + name = "MacGPSBabel.applescript: 815"; + rLen = 0; + rLoc = 35444; + rType = 0; + vrLen = 1617; + vrLoc = 22605; + }; + 3FB41B8C06EFB84A0017502D = { + fRef = DA206CF4015C4E8B03C91932; + fallbackIsa = PBXBookmark; + isa = ASKDictionaryBookmark; + }; + DA206CF0015C4D9F03C91932 = { + activeArgIndex = 2147483647; + activeArgIndices = ( + ); + argumentStrings = ( + ); + configStateDict = { + }; + cppStopOnCatchEnabled = 0; + cppStopOnThrowEnabled = 0; + customDataFormattersEnabled = 1; + debuggerPlugin = ASKDebugger; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + isa = PBXExecutable; + libgmallocEnabled = 0; + name = MacGPSBabel; + shlibInfoDictList = ( + ); + sourceDirectories = ( + ); + }; + DA206CF3015C4E8B03C91932 = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1672, 12585}}"; + sepNavSelRange = "{35550, 0}"; + sepNavVisRect = "{{0, 8145}, {862, 533}}"; + }; + }; +} diff --git a/macgpsbabel/MacGPSBabel.pbproj/project.pbxproj b/macgpsbabel/MacGPSBabel.pbproj/project.pbxproj new file mode 100644 index 000000000..c2d2aad14 --- /dev/null +++ b/macgpsbabel/MacGPSBabel.pbproj/project.pbxproj @@ -0,0 +1,480 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 39; + objects = { + 080E96DDFE201D6D7F000001 = { + children = ( + DA206CF3015C4E8B03C91932, + ); + isa = PBXGroup; + name = Scripts; + refType = 4; + sourceTree = ""; + }; + 089C165CFE840E0CC02AAC07 = { + children = ( + 089C165DFE840E0CC02AAC07, + F508F3FF05A7A82F01A80064, + ); + isa = PBXVariantGroup; + name = InfoPlist.strings; + refType = 4; + sourceTree = ""; + }; + 089C165DFE840E0CC02AAC07 = { + fileEncoding = 10; + isa = PBXFileReference; + lastKnownFileType = text.plist.strings; + name = English; + path = English.lproj/InfoPlist.strings; + refType = 4; + sourceTree = ""; + }; + 089C165EFE840E0CC02AAC07 = { + fileRef = 089C165CFE840E0CC02AAC07; + isa = PBXBuildFile; + settings = { + }; + }; +//080 +//081 +//082 +//083 +//084 +//100 +//101 +//102 +//103 +//104 + 1058C7A0FEA54F0111CA2CBB = { + children = ( + 1058C7A1FEA54F0111CA2CBB, + DA206CF1015C4E2903C91932, + ); + isa = PBXGroup; + name = "Linked Frameworks"; + refType = 4; + sourceTree = ""; + }; + 1058C7A1FEA54F0111CA2CBB = { + isa = PBXFileReference; + lastKnownFileType = wrapper.framework; + name = Cocoa.framework; + path = /System/Library/Frameworks/Cocoa.framework; + refType = 0; + sourceTree = ""; + }; + 1058C7A2FEA54F0111CA2CBB = { + children = ( + 29B97325FDCFA39411CA2CEA, + 29B97324FDCFA39411CA2CEA, + ); + isa = PBXGroup; + name = "Other Frameworks"; + refType = 4; + sourceTree = ""; + }; + 1058C7A3FEA54F0111CA2CBB = { + fileRef = 1058C7A1FEA54F0111CA2CBB; + isa = PBXBuildFile; + settings = { + }; + }; +//100 +//101 +//102 +//103 +//104 +//170 +//171 +//172 +//173 +//174 + 17587328FF379C6511CA2CBB = { + explicitFileType = wrapper.application; + isa = PBXFileReference; + path = MacGPSBabel.app; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; +//170 +//171 +//172 +//173 +//174 +//190 +//191 +//192 +//193 +//194 + 19C28FACFE9D520D11CA2CBB = { + children = ( + 17587328FF379C6511CA2CBB, + ); + isa = PBXGroup; + name = Products; + refType = 4; + sourceTree = ""; + }; +//190 +//191 +//192 +//193 +//194 +//290 +//291 +//292 +//293 +//294 + 29B97313FDCFA39411CA2CEA = { + buildSettings = { + }; + buildStyles = ( + 4A9504CCFFE6A4B311CA0CBA, + 4A9504CDFFE6A4B311CA0CBA, + ); + hasScannedForEncodings = 1; + isa = PBXProject; + mainGroup = 29B97314FDCFA39411CA2CEA; + projectDirPath = ""; + targets = ( + 29B97326FDCFA39411CA2CEA, + ); + }; + 29B97314FDCFA39411CA2CEA = { + children = ( + 080E96DDFE201D6D7F000001, + 29B97317FDCFA39411CA2CEA, + 29B97315FDCFA39411CA2CEA, + 29B97323FDCFA39411CA2CEA, + 19C28FACFE9D520D11CA2CBB, + ); + isa = PBXGroup; + name = Application; + path = ""; + refType = 4; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA = { + children = ( + 29B97316FDCFA39411CA2CEA, + ); + isa = PBXGroup; + name = "Other Sources"; + path = ""; + refType = 4; + sourceTree = ""; + }; + 29B97316FDCFA39411CA2CEA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = main.m; + refType = 4; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA = { + children = ( + 29B97319FDCFA39411CA2CEA, + 089C165CFE840E0CC02AAC07, + DA206CF4015C4E8B03C91932, + F52E6CB4059959B801A80064, + F514A08D05A6164F01A80064, + ); + isa = PBXGroup; + name = Resources; + path = ""; + refType = 4; + sourceTree = ""; + }; + 29B97319FDCFA39411CA2CEA = { + isa = PBXFileReference; + lastKnownFileType = wrapper.nib; + path = MainMenu.nib; + refType = 4; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA = { + children = ( + 1058C7A0FEA54F0111CA2CBB, + 1058C7A2FEA54F0111CA2CBB, + ); + isa = PBXGroup; + name = Frameworks; + path = ""; + refType = 4; + sourceTree = ""; + }; + 29B97324FDCFA39411CA2CEA = { + isa = PBXFileReference; + lastKnownFileType = wrapper.framework; + name = AppKit.framework; + path = /System/Library/Frameworks/AppKit.framework; + refType = 0; + sourceTree = ""; + }; + 29B97325FDCFA39411CA2CEA = { + isa = PBXFileReference; + lastKnownFileType = wrapper.framework; + name = Foundation.framework; + path = /System/Library/Frameworks/Foundation.framework; + refType = 0; + sourceTree = ""; + }; + 29B97326FDCFA39411CA2CEA = { + buildPhases = ( + 29B97327FDCFA39411CA2CEA, + DA7CAE8F015CFCCA03C91932, + 29B97328FDCFA39411CA2CEA, + 29B9732BFDCFA39411CA2CEA, + 29B9732DFDCFA39411CA2CEA, + ); + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ""; + HEADER_SEARCH_PATHS = ""; + INSTALL_PATH = "$(HOME)/Applications"; + LIBRARY_SEARCH_PATHS = /Users/jeremya/Dev/MacGPSBabel; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = MacGPSBabel; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; + WRAPPER_EXTENSION = app; + }; + dependencies = ( + ); + isa = PBXApplicationTarget; + name = MacGPSBabel; + productInstallPath = "$(HOME)/Applications"; + productName = Application; + productReference = 17587328FF379C6511CA2CBB; + productSettingsXML = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + MacGPSBabel + CFBundleIconFile + mgb.icns + CFBundleIdentifier + com.gpsbabel.MacGPSBabel + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + mGPS + CFBundleVersion + 1.0.6 + NSAppleScriptEnabled + YES + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + +"; + }; + 29B97327FDCFA39411CA2CEA = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXHeadersBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 29B97328FDCFA39411CA2CEA = { + buildActionMask = 2147483647; + files = ( + 3FC2F7BD06EE9EDE002083D3, + 089C165EFE840E0CC02AAC07, + F52E6CB5059959B801A80064, + F514A08E05A6164F01A80064, + ); + isa = PBXResourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 29B9732BFDCFA39411CA2CEA = { + buildActionMask = 2147483647; + files = ( + 29B9732CFDCFA39411CA2CEA, + ); + isa = PBXSourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 29B9732CFDCFA39411CA2CEA = { + fileRef = 29B97316FDCFA39411CA2CEA; + isa = PBXBuildFile; + settings = { + ATTRIBUTES = ( + ); + }; + }; + 29B9732DFDCFA39411CA2CEA = { + buildActionMask = 2147483647; + files = ( + 1058C7A3FEA54F0111CA2CBB, + DA206CF2015C4E2903C91932, + ); + isa = PBXFrameworksBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; +//290 +//291 +//292 +//293 +//294 +//3F0 +//3F1 +//3F2 +//3F3 +//3F4 + 3FC2F7BD06EE9EDE002083D3 = { + fileRef = 29B97319FDCFA39411CA2CEA; + isa = PBXBuildFile; + settings = { + }; + }; +//3F0 +//3F1 +//3F2 +//3F3 +//3F4 +//4A0 +//4A1 +//4A2 +//4A3 +//4A4 + 4A9504CCFFE6A4B311CA0CBA = { + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + OPTIMIZATION_CFLAGS = "-O0"; + ZERO_LINK = YES; + }; + isa = PBXBuildStyle; + name = Development; + }; + 4A9504CDFFE6A4B311CA0CBA = { + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + OTHER_OSAFLAGS = "-x"; + ZERO_LINK = NO; + }; + isa = PBXBuildStyle; + name = Deployment; + }; +//4A0 +//4A1 +//4A2 +//4A3 +//4A4 +//DA0 +//DA1 +//DA2 +//DA3 +//DA4 + DA206CF1015C4E2903C91932 = { + isa = PBXFileReference; + lastKnownFileType = wrapper.framework; + name = AppleScriptKit.framework; + path = /System/Library/Frameworks/AppleScriptKit.framework; + refType = 0; + sourceTree = ""; + }; + DA206CF2015C4E2903C91932 = { + fileRef = DA206CF1015C4E2903C91932; + isa = PBXBuildFile; + settings = { + }; + }; + DA206CF3015C4E8B03C91932 = { + explicitFileType = sourcecode.applescript; + fileEncoding = 30; + isa = PBXFileReference; + path = MacGPSBabel.applescript; + refType = 4; + sourceTree = ""; + }; + DA206CF4015C4E8B03C91932 = { + isa = PBXFileReference; + lastKnownFileType = archive.asdictionary; + name = AppleScriptKit.asdictionary; + path = /System/Library/Frameworks/AppleScriptKit.framework/Versions/A/Resources/AppleScriptKit.asdictionary; + refType = 0; + sourceTree = ""; + }; + DA206CF5015C4E8B03C91932 = { + fileRef = DA206CF3015C4E8B03C91932; + isa = PBXBuildFile; + settings = { + ATTRIBUTES = ( + Debug, + ); + }; + }; + DA7CAE8F015CFCCA03C91932 = { + buildActionMask = 2147483647; + contextName = ""; + files = ( + DA206CF5015C4E8B03C91932, + ); + isSharedContext = 0; + isa = PBXAppleScriptBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; +//DA0 +//DA1 +//DA2 +//DA3 +//DA4 +//F50 +//F51 +//F52 +//F53 +//F54 + F508F3FF05A7A82F01A80064 = { + isa = PBXFileReference; + lastKnownFileType = text.rtf; + path = Credits.rtf; + refType = 4; + sourceTree = ""; + }; + F514A08D05A6164F01A80064 = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.executable"; + path = gpsbabel; + refType = 4; + sourceTree = ""; + }; + F514A08E05A6164F01A80064 = { + fileRef = F514A08D05A6164F01A80064; + isa = PBXBuildFile; + settings = { + }; + }; + F52E6CB4059959B801A80064 = { + isa = PBXFileReference; + lastKnownFileType = image.icns; + path = mgb.icns; + refType = 4; + sourceTree = ""; + }; + F52E6CB5059959B801A80064 = { + fileRef = F52E6CB4059959B801A80064; + isa = PBXBuildFile; + settings = { + }; + }; + }; + rootObject = 29B97313FDCFA39411CA2CEA; +} diff --git a/macgpsbabel/README.macgpsbabel b/macgpsbabel/README.macgpsbabel new file mode 100644 index 000000000..e4d7ee848 --- /dev/null +++ b/macgpsbabel/README.macgpsbabel @@ -0,0 +1,8 @@ +MacGPSBabel is a Mac OS X GUI front-end for gpsbabel. The GUI was developed using Apple's 'Interface Builder' application and the code to link the GUI to gpsbabel is written in Applescript. + +Build instructions. + +MacGPSBabel can be built with Apple's developer tools in the same way that you would build any other application. As it is, the Project Builder will assume that you have added a build of gpsbabel into the same folder as the rest of the MacGPSBabel project files. This binary will then be embedded in the build of MacGPSBabel. If you do not do this then MacGPSBabel will not work, however, it is possible to place the gpsbabel binary into the Resources Folder in the MacGPSBabel package after building it. + +Debug (verbose) Mode +This can be activated by pressing command-option-v whilst the main MacGPSBabel window is the active window. When debug mode is active, using MacGPSBabel in the usual manner will result in a report for each file conversion being displayed in the debug window. Alternatively, commands can be typed directly in the debug window and run using the 'execute' button (the full path to any file needs to be specified). \ No newline at end of file diff --git a/macgpsbabel/main.m b/macgpsbabel/main.m new file mode 100644 index 000000000..6c4fdb11e --- /dev/null +++ b/macgpsbabel/main.m @@ -0,0 +1,9 @@ +extern void ASKInitialize(); +extern int NSApplicationMain(int argc, const char *argv[]); + +int main(int argc, const char *argv[]) +{ + ASKInitialize(); + + return NSApplicationMain(argc, argv); +} diff --git a/macgpsbabel/mgb.icns b/macgpsbabel/mgb.icns new file mode 100644 index 0000000000000000000000000000000000000000..01c5972d6b755952b4cee91f7a0689a396563b31 GIT binary patch literal 33545 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 Qg#FVB{Iml9@2tT80qY$aCIA2c literal 0 HcmV?d00001 diff --git a/macgpsbabel/preferences.applescript b/macgpsbabel/preferences.applescript new file mode 100644 index 000000000..2f7e62d58 --- /dev/null +++ b/macgpsbabel/preferences.applescript @@ -0,0 +1,185 @@ +-- MacGPSBabel: preferences.applescript +-- File Created by Jeremy Atherton on January 30, 2004 +-- Last modified by Jeremy Atherton on Monday, February 16, 2004 + +-- MacGPSBabel is part of the gpsbabel project and is Copyright (c) 2004 Robert Lipe. +-- see http://gpsbabel.sourceforge.net/ for more details + +-- This script (preferences.applescript) deals mostly with reading and saving user defaults. Along the way, it also deals with getting the list of available serial ports. + +-- PROPERTIES -- +property startIndex : 0 +property startState : false + +-- EVENT HANDLERS -- + +on will finish launching theObject + -- make empty entries in user defaults + make new default entry at end of default entries of user defaults with properties {name:"theInputType", contents:startIndex} + make new default entry at end of default entries of user defaults with properties {name:"theOutputType", contents:startIndex} + make new default entry at end of default entries of user defaults with properties {name:"gpsIN", contents:startState} + make new default entry at end of default entries of user defaults with properties {name:"gpsOUT", contents:startState} + make new default entry at end of default entries of user defaults with properties {name:"gpsReceiver", contents:startIndex} +end will finish launching + +on awake from nib theObject + if theObject is window "MacGPSBabel" then + tell window "MacGPSBabel" + set popList to my getFormats() + repeat with i in popList + make new menu item at the end of menu items of menu of popup button "inPop" with properties {title:i, enabled:true} + make new menu item at the end of menu items of menu of popup button "outPop" with properties {title:i, enabled:true} + end repeat + end tell + + -- read current user defaults + my readSettings() + + -- deal with changes to MacGPSBabel window needed if any of the GPS check boxes are checked by default + if state of button "GPSswitchIN" of window "MacGPSBabel" is equal to 1 then + my gpsIN() + end if + if state of button "GPSswitchOUT" of window "MacGPSBabel" is equal to 1 then + my gpsOUT() + end if + end if +end awake from nib + +on will open theObject + -- set the progress indicator style + if theObject is window "MacGPSBabel" then + set p to progress indicator 1 of theObject + call method "setStyle:" of p with parameter 1 + call method "setDisplayedWhenStopped:" of p with parameters {false} + end if + if theObject is window "SelectGPS" then + -- get the list of available serial ports + set popList to my getSerial() + -- use popList to populate the drop-down menu + delete every menu item of menu of popup button "serialPop" of window "SelectGPS" + repeat with i in popList + make new menu item at the end of menu items of menu of popup button "serialPop" of window "SelectGPS" with properties {title:i, enabled:true} + end repeat + + -- read user defaults for this window + tell user defaults + set defaultgpsReceiver to contents of default entry "gpsReceiver" + end tell + set state of popup button "gpsPop" of window "SelectGPS" to defaultgpsReceiver + + -- hide MacGPSBabel window + set visible of window "MacGPSBabel" to false + end if +end will open + +on will close theObject + if theObject is window "SelectGPS" then + -- store user defaults for this window + set newReceiverIndex to contents of popup button "gpsPop" of window "SelectGPS" + tell user defaults + set contents of default entry "gpsReceiver" to newReceiverIndex + end tell + + -- unhide MacGPSBabel window + set visible of window "MacGPSBabel" to true + end if +end will close + +-- store user defaults for MacGPSBabel window +on clicked theObject + if theObject is button "defaultsButton" of window "MacGPSBabel" then + set newInputIndex to contents of popup button "inPop" of window "MacGPSBabel" + set newOutputIndex to contents of popup button "outPop" of window "MacGPSBabel" + set newINstate to state of button "GPSswitchIN" of window "MacGPSBabel" as boolean + set newOUTstate to state of button "GPSswitchOUT" of window "MacGPSBabel" as boolean + tell user defaults + set contents of default entry "theInputType" to newInputIndex + set contents of default entry "theOutputType" to newOutputIndex + set contents of default entry "gpsIN" to newINstate + set contents of default entry "gpsOUT" to newOUTstate + end tell + end if +end clicked + +-- HANDLERS -- + +-- read user defaults +on readSettings() + tell user defaults + set defaultInputIndex to contents of default entry "theInputType" as integer + set defaultOutputIndex to contents of default entry "theOutputType" as integer + set defaultgpsIN to contents of default entry "gpsIN" as boolean + set defaultgpsOUT to contents of default entry "gpsOUT" as boolean + end tell + -- call method "setObjectValue:" of object (popup button "inPop" of window "MacGPSBabel") with parameter defaultInputIndex + -- call method "synchronizeTitleAndSelectedItem" of object (popup button "inPop" of window "MacGPSBabel") + set contents of popup button "inPop" of window "MacGPSBabel" to defaultInputIndex + set contents of popup button "outPop" of window "MacGPSBabel" to defaultOutputIndex + set state of button "GPSswitchIN" of window "MacGPSBabel" to defaultgpsIN + set state of button "GPSswitchOUT" of window "MacGPSBabel" to defaultgpsOUT +end readSettings + +-- scripts for dealing with GPS checkboxes on MacGPSBabel window +on gpsIN() + if state of button "GPSswitchIN" of window "MacGPSBabel" = 1 then + set enabled of button "selectButton" of window "MacGPSBabel" to false + set enabled of button "clearButton" of window "MacGPSBabel" to false + set enabled of button "sendButton" of window "MacGPSBabel" to true + set contents of text field "inputFile" of window "MacGPSBabel" to "" + set enabled of text field "inputFile" of window "MacGPSBabel" to false + set enabled of popup button "inPop" of window "MacGPSBabel" to false + else + set enabled of button "selectButton" of window "MacGPSBabel" to true + set enabled of button "sendButton" of window "MacGPSBabel" to false + set enabled of text field "inputFile" of window "MacGPSBabel" to true + set enabled of popup button "inPop" of window "MacGPSBabel" to true + end if +end gpsIN +on gpsOUT() + if state of button "GPSswitchOUT" of window "MacGPSBabel" = 1 then + set enabled of popup button "outPop" of window "MacGPSBabel" to false + else + set enabled of popup button "outPop" of window "MacGPSBabel" to true + end if +end gpsOUT + +-- find the serial ports +on getSerial() + set myList to {} + set theScript to "cd /dev; ls | grep cu\\." + set scriptOut to (do shell script theScript) as string + set theCount to count of paragraphs in scriptOut + set i to 0 + set defaultDelimiters to AppleScript's text item delimiters + set AppleScript's text item delimiters to {"."} + repeat until i = theCount + set i to i + 1 + set theWords to the count of text items in paragraph i of scriptOut + set z to 2 + set the end of myList to (text items z thru theWords of paragraph i of scriptOut) as string + end repeat + set AppleScript's text item delimiters to defaultDelimiters + return myList +end getSerial + +-- handler (called at startup) to check with GPS Babel which file formats it can handle. Return the result as a list +on getFormats() + set myList to {} + set typeList to {} + set extList to {} + set thePath to POSIX path of (path to me) as string + set scriptOut to (do shell script quoted form of thePath & "Contents/Resources/gpsbabel -^1") as string + set theCount to count of paragraphs in scriptOut + set defaultDelimiters to AppleScript's text item delimiters + set AppleScript's text item delimiters to tab + repeat with i from 1 to theCount + set theLine to paragraph i of scriptOut + if (first text item of theLine) is equal to "file" then + set the end of typeList to the second text item of theLine + set the end of extList to the third text item of theLine + set the end of myList to the last text item of theLine + end if + end repeat + set AppleScript's text item delimiters to defaultDelimiters + return myList +end getFormats \ No newline at end of file diff --git a/magellan.h b/magellan.h new file mode 100644 index 000000000..f7a023b16 --- /dev/null +++ b/magellan.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +/* + * Table of "interesting" Magellan models. + * Selfishly, if I haven't heard of it, it's not in the table. + * This doesn't mean I actually have TRIED all models listed below. + * (Donations welcome. :-) + */ +typedef enum { + mm_unknown = 0 , + mm_gps315320, + mm_map410, + mm_map330, + mm_gps310, + mm_meridian, + mm_sportrak +} meridian_model; + +typedef struct pid_to_model { + meridian_model model; + int pid; + const char *model_n; +} pid_to_model_t; + +typedef struct icon_mapping { + const char *token; + const char *icon; +} icon_mapping_t; + +const char * mag_find_descr_from_token(const char *token); +const char * mag_find_token_from_descr(const char *icon); + +waypoint * mag_trkparse(char *trkmsg); +void mag_rteparse(char *rtemsg); diff --git a/magnav.c b/magnav.c new file mode 100644 index 000000000..392974e40 --- /dev/null +++ b/magnav.c @@ -0,0 +1,273 @@ +/* + Read and write Magellan Navigator Companion files. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "coldsync/palm.h" +#include "coldsync/pdb.h" + +#define MYNAME "Companion Waypoints" +#define MYTYPE 0x54777074 /* Twpt */ +#define MYCREATOR 0x4d47747a /* MGtz */ + +struct record { + pdb_16 crt_sec; /* Big endian, creation time */ + pdb_16 crt_min; + pdb_16 crt_hour; + pdb_16 crt_mday; + pdb_16 crt_mon; /* 1 = Jan */ + pdb_16 crt_year; /* includes century. */ + pdb_16 unknown; + pdb_16 xx_sec; /* appears to be time, but we don't know what it is. */ + pdb_16 xx_min; + pdb_16 xx_hour; + pdb_16 xx_mday; + pdb_16 xx_mon; + pdb_16 xx_year; + pdb_16 unknown2; + pdb_32 latitude; /* lat * 1e5 */ + pdb_32 longitude; /* lon * 1e5 */ + pdb_32 elevation; /* meters */ + char plot; /* 1 = plot on map screen. default = 0 */ + char unknown3; /* always 'a' */ +}; + +static FILE *file_in; +static FILE *file_out; +static const char *out_fname; +static void *mkshort_handle; + +struct pdb *opdb; +struct pdb_record *opdb_rec; + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "rb", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "wb", MYNAME); + out_fname = fname; + mkshort_handle = mkshort_new_handle(); + setshort_length(mkshort_handle, 20); +} + +static void +wr_deinit(void) +{ + fclose(file_out); + mkshort_del_handle(mkshort_handle); +} + +static void +data_read(void) +{ + struct record *rec; + struct pdb *pdb; + struct pdb_record *pdb_rec; + + if (NULL == (pdb = pdb_Read(fileno(file_in)))) { + fatal(MYNAME ": pdb_Read failed\n"); + } + + if ((pdb->creator != MYCREATOR) || (pdb->type != MYTYPE)) { + fatal(MYNAME ": Not a Magellan Navigator file.\n"); + } + + for(pdb_rec = pdb->rec_index.rec; pdb_rec; pdb_rec=pdb_rec->next) { + waypoint *wpt_tmp; + char *vdata; + struct tm tm; + + memset (&tm, sizeof(tm), 0); + wpt_tmp = xcalloc(sizeof(*wpt_tmp),1); + rec = (struct record *) pdb_rec->data; + wpt_tmp->altitude = be_read32(&rec->elevation); + + wpt_tmp->longitude = be_read32(&rec->longitude) / 1e5; + wpt_tmp->latitude = be_read32(&rec->latitude) / 1e5; + + vdata = (char *) pdb_rec->data + sizeof(*rec); + + wpt_tmp->shortname = xstrdup(vdata); + vdata += strlen (vdata) + 1; + + wpt_tmp->description = xstrdup(vdata); + vdata += strlen (vdata) + 1; + + tm.tm_sec = be_read16(&rec->crt_sec); + tm.tm_min = be_read16(&rec->crt_min); + tm.tm_hour = be_read16(&rec->crt_hour); + tm.tm_mday = be_read16(&rec->crt_mday); + tm.tm_mon = be_read16(&rec->crt_mon) - 1; + tm.tm_year = be_read16(&rec->crt_year) - 1900; + wpt_tmp->creation_time = mktime(&tm); + + waypt_add(wpt_tmp); + + } + free_pdb(pdb); +} + + +static void +my_writewpt(const waypoint *wpt) +{ + struct record *rec; + static int ct; + struct tm *tm; + char *vdata; + time_t tm_t; + const char *sn = global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, wpt->description) : + wpt->shortname; + + rec = xcalloc(sizeof(*rec)+56,1); + + tm = NULL; + if ( wpt->creation_time ) { + tm = gmtime( &wpt->creation_time); + } + if ( !tm ) { + tm_t = current_time(); + tm = gmtime( &tm_t ); + } + + be_write16( &rec->crt_sec, tm->tm_sec ); + be_write16( &rec->crt_min, tm->tm_min ); + be_write16( &rec->crt_hour, tm->tm_hour ); + be_write16( &rec->crt_mday, tm->tm_mday ); + be_write16( &rec->crt_mon, tm->tm_mon + 1 ); + be_write16( &rec->crt_year, tm->tm_mon + 1900 ); + + be_write16( &rec->unknown, 0); + + be_write16( &rec->xx_sec, tm->tm_sec ); + be_write16( &rec->xx_min, tm->tm_min ); + be_write16( &rec->xx_hour, tm->tm_hour ); + be_write16( &rec->xx_mday, tm->tm_mday ); + be_write16( &rec->xx_mon, tm->tm_mon + 1 ); + be_write16( &rec->xx_year, tm->tm_mon + 1900 ); + + be_write16( &rec->unknown2, 0); + + be_write32(&rec->longitude, si_round(wpt->longitude * 100000.0)); + be_write32(&rec->latitude, si_round(wpt->latitude * 100000.0)); + be_write32(&rec->elevation, wpt->altitude); + + rec->plot = 0; + rec->unknown3 = 'a'; + + vdata = (char *)rec + sizeof(*rec); + if ( sn ) { + strncpy( vdata, sn, 21 ); + vdata[20] = '\0'; + } + else { + vdata[0] ='\0'; + } + vdata += strlen( vdata ) + 1; + if ( wpt->description ) { + strncpy( vdata, wpt->description, 33 ); + vdata[32] = '\0'; + } + else { + vdata[0] = '\0'; + } + vdata += strlen( vdata ) + 1; + vdata[0] = '\0'; + vdata[1] = '\0'; + vdata += 2; + + opdb_rec = new_Record (0, 0, ct++, vdata-(char *)rec, (const ubyte *)rec); + + if (opdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create record\n"); + } + + if (pdb_AppendRecord(opdb, opdb_rec)) { + fatal(MYNAME ": libpdb couldn't append record\n"); + } + xfree(rec); +} + +static void +data_write(void) +{ + static char *appinfo = + "\0\x01" + "User\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\0\0"; + + if (NULL == (opdb = new_pdb())) { + fatal (MYNAME ": new_pdb failed\n"); + } + + strncpy(opdb->name, "Companion Waypoints", PDB_DBNAMELEN); + opdb->name[PDB_DBNAMELEN-1] = 0; + opdb->attributes = PDB_ATTR_BACKUP; + opdb->ctime = opdb->mtime = current_time() + 2082844800U; + opdb->type = MYTYPE; /* CWpt */ + opdb->creator = MYCREATOR; /* cGPS */ + opdb->version = 1; + opdb->appinfo = (void *)appinfo; + opdb->appinfo_len = 276; + + waypt_disp_all(my_writewpt); + + pdb_Write(opdb, fileno(file_out)); +} + + +ff_vecs_t magnav_vec = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL +}; diff --git a/magproto.c b/magproto.c new file mode 100644 index 000000000..87424e204 --- /dev/null +++ b/magproto.c @@ -0,0 +1,1409 @@ +/* + Communicate Thales/Magellan serial protocol. + + Copyright (C) 2002, 2003, 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include + +#include "defs.h" +#include "magellan.h" + +int bitrate = 4800; +#define MYNAME "MAGPROTO" + +#define debug_serial (global_opts.debug_level > 1) + +static char * termread(char *ibuf, int size); +static void termwrite(char *obuf, int size); +static void mag_readmsg(void); +static void mag_handon(void); +static void mag_handoff(void); +static void *mkshort_handle = NULL; +static char *deficon = NULL; +static char *bs = NULL; +static char *noack = NULL; +static char *nukewpt = NULL; +static int route_out_count; +static int waypoint_read_count; + +typedef enum { + mrs_handoff = 0, + mrs_handon, + mrs_awaiting_ack +} mag_rxstate; + +/* + * An individual element of a route. + */ +typedef struct mag_rte_elem { + queue Q; /* My link pointers */ + char *wpt_name; + char *wpt_icon; +} mag_rte_elem; + +/* + * A header of a route. Related elements of a route belong to this. + */ +typedef struct mag_rte_head { + queue Q; /* Queue head for child rte_elems */ + int nelems; +} mag_rte_head; + +static queue rte_wpt_tmp; /* temporary PGMNWPL msgs for routes */ + +static FILE *magfile_in; +static FILE *magfile_out; +static int magfd; +static mag_rxstate magrxstate; +static int mag_error; +static unsigned int last_rx_csum; +static int found_done; +static int got_version; +static int is_file = 0; +static route_head *trk_head; +static int ignore_unable; + +static waypoint * mag_wptparse(char *); +typedef char * (cleanse_fn) (char *); +static cleanse_fn *mag_cleanse; + +static icon_mapping_t gps315_icon_table[] = { + { "a", "filled circle" }, + { "b", "box" }, + { "c", "red buoy" }, + { "d", "green buoy" }, + { "e", "buoy" }, + { "f", "rocks" }, + { "g", "red daymark" }, + { "h", "green daymark" }, + { "i", "bell" }, + { "j", "danger" }, + { "k", "diver down" }, + { "l", "fish" }, + { "m", "house" }, + { "n", "mark" }, + { "o", "car" }, + { "p", "tent" }, + { "q", "boat" }, + { "r", "food" }, + { "s", "fuel" }, + { "t", "tree" }, + { NULL, NULL } +}; + +static icon_mapping_t map330_icon_table[] = { + { "a", "crossed square" }, + { "b", "box" }, + { "c", "house" }, + { "d", "aerial" }, + { "e", "airport" }, + { "f", "amusement park" }, + { "g", "ATM" }, + { "g", "Bank" }, + { "h", "auto repair" }, + { "i", "boating" }, + { "j", "camping" }, + { "k", "exit ramp" }, + { "l", "first aid" }, + { "m", "nav aid" }, + { "n", "buoy" }, + { "o", "fuel" }, + { "p", "garden" }, + { "q", "golf" }, + { "r", "hotel" }, + { "s", "hunting/fishing" }, + { "t", "large city" }, + { "u", "lighthouse" }, + { "v", "major city" }, + { "w", "marina" }, + { "x", "medium city" }, + { "y", "museum" }, + { "z", "obstruction" }, + { "aa", "park" }, + { "ab", "resort" }, + { "ac", "restaurant" }, + { "ad", "rock" }, + { "ae", "scuba" }, + { "af", "RV service" }, + { "ag", "shooting" }, + { "ah", "sight seeing" }, + { "ai", "small city" }, + { "aj", "sounding" }, + { "ak", "sports arena" }, + { "al", "tourist info" }, + { "am", "truck service" }, + { "an", "winery" }, + { "ao", "wreck" }, + { "ap", "zoo" }, + { "ah", "Virtual cache"}, /* Binos: because you "see" them. */ + { "ak", "Micro-Cache" }, /* Looks like a film canister. */ + { "an", "Multi-Cache"}, /* Winery: grapes 'coz they "bunch" */ + { "s", "Unknown Cache"}, /* 'Suprise' cache: use a target. */ + { "ac", "Event Cache"}, /* Event caches. May be food. */ + { NULL, NULL } +}; + +pid_to_model_t pid_to_model[] = +{ + { mm_gps315320, 19, "ColorTrak" }, + { mm_gps315320, 24, "GPS 315/320" }, + { mm_map410, 25, "Map 410" }, + { mm_map330, 30, "Map 330" }, + { mm_gps310, 31, "GPS 310" }, + { mm_meridian, 33, "Meridian" }, + { mm_meridian, 35, "ProMark 2" }, + { mm_sportrak, 36, "SporTrak Map/Pro" }, + { mm_sportrak, 37, "SporTrak" }, + { mm_meridian, 39, "Meridian Color" }, + { mm_sportrak, 41, "Sportrak Color" }, + { mm_sportrak, 42, "Sportrak Marine" }, + { mm_meridian, 43, "Meridian Marine" }, + { mm_sportrak, 44, "Sportrak Topo" }, + { mm_sportrak, 45, "Mystic" }, + { mm_meridian, 46, "MobileMapper" }, + { mm_unknown, 0, NULL } +}; + +static icon_mapping_t *icon_mapping = map330_icon_table; + +/* + * For each receiver type, return a "cleansed" version of the string + * that's valid for a waypoint name or comment. The string should be + * freed when you're done with it. + */ +static char * +m315_cleanse(char *istring) +{ + char *rstring = xmalloc(strlen(istring)+1); + char *i,*o; + static char m315_valid_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789"; + for (o=rstring,i=istring; *i; i++) { + if (strchr(m315_valid_chars, toupper(*i))) { + *o++ = toupper(*i); + } + } + *o = 0; + return rstring; +} + +/* + * Do same for 330, Meridian, and SportTrak. + */ +static char * +m330_cleanse(char *istring) +{ + static char m330_valid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ " + "abcdefghijklmnopqrstuvwxyz" + "0123456789+-.'/!@#<%^&>()=:\\"; + char *rstring = xmalloc(strlen(istring)+1); + char *o, *i; + + for (o=rstring,i=istring; *i;i++) { + if (strchr(m330_valid_chars, *i)) { + *o++ = *i; + } + } + *o = 0; + return rstring; +} + +/* + * Given a protocol message, compute the checksum as needed by + * the Magellan protocol. + */ +static unsigned int +mag_checksum(const char * const buf) +{ + int csum = 0; + const char *p; + + for(p = buf; *p; p++) { + csum ^= *p; + } + + return csum; +} +static unsigned int +mag_pchecksum(const char * const buf, int len) +{ + int csum = 0; + const char *p = buf; + for (; len ; len--) { + csum ^= *p++; + } + return csum; +} + +static void +mag_writemsg(const char * const buf) +{ + unsigned int osum = mag_checksum(buf); + int retry_cnt = 20; + int i; + char obuf[1000]; + + if (debug_serial) { + warning("WRITE: $%s*%02X\r\n",buf, osum); + } + + retry: + + i = sprintf(obuf, "$%s*%02X\r\n",buf, osum); + termwrite(obuf, i); + if (magrxstate == mrs_handon || magrxstate == mrs_awaiting_ack) { + magrxstate = mrs_awaiting_ack; + mag_readmsg(); + if (last_rx_csum != osum) { + if (debug_serial) { + warning("COMM ERROR: Expected %02x, got %02x", + osum, last_rx_csum); + } + if (retry_cnt--) + goto retry; + else { + mag_handoff(); + fatal(MYNAME + ": Too many communication errors.\n"); + } + } + } +} + +static void +mag_writeack(int osum) +{ + char obuf[200]; + char nbuf[200]; + int i; + unsigned int nsum; + + if (is_file) { + return; + } + + i = sprintf(nbuf, "PMGNCSM,%02X", osum); + nsum = mag_checksum(nbuf); + i = sprintf(obuf, "$%s*%02X\r\n",nbuf, nsum); + + if (debug_serial) { + warning("ACK WRITE: %s",obuf); + } + /* + * Don't call mag_writemsg here so we don't get into ack feedback + * loops. + */ + termwrite(obuf, i); +} + +static void +mag_handon(void) +{ + if (!is_file) { + mag_writemsg("PMGNCMD,HANDON"); + } + magrxstate = mrs_handon; + +} + +static void +mag_handoff(void) +{ + if (!is_file) { + mag_writemsg("PMGNCMD,HANDOFF"); + } + magrxstate = mrs_handoff; +} + +void +mag_verparse(char *ibuf) +{ + int prodid = mm_unknown; + char version[1024]; + pid_to_model_t *pp = pid_to_model; + + got_version = 1; + sscanf(ibuf,"$PMGNVER,%d,%[^,]", &prodid, version); + + for (pp = pid_to_model; pp->model != mm_unknown; pp++) { + if (pp->pid == prodid) { + break; + } + } + switch (pp->model) { + case mm_gps315320: + case mm_map410: + icon_mapping = gps315_icon_table; + setshort_length(mkshort_handle, 6); + setshort_mustupper(mkshort_handle, 1); + mag_cleanse = m315_cleanse; + break; + case mm_map330: + case mm_meridian: + case mm_sportrak: + icon_mapping = map330_icon_table; + setshort_length(mkshort_handle, 8); + setshort_mustupper(mkshort_handle, 0); + mag_cleanse = m330_cleanse; + break; + default: + fatal(MYNAME ": Unknown receiver type %d, model version '%s'.\n", prodid, version); + } +} + +#define IS_TKN(x) (strncmp(ibuf,x, sizeof(x)-1) == 0) + +static void +mag_readmsg(void) +{ + char ibuf[200]; + int isz; + unsigned int isum; + char *isump; + char *gr; + int retrycnt = 20; + +retry: + gr = termread(ibuf, sizeof(ibuf)); + + if (!gr) { + if (!got_version) { + /* + * The 315 can take up to six seconds to respond to + * a VERSION command. Since this is on startup, + * we'll be fairly persistent in retrying. + */ + if (retrycnt--) { + goto retry; + } else { + fatal(MYNAME ": No data received from GPS.\n"); + } + } else { + if (is_file) { + found_done = 1; + } + return; + } + } + + isz = strlen(ibuf); + + if (isz < 5) { + if (debug_serial) + warning( "SHORT READ %d\n", isz); + return; + } + mag_error = 0; + while (!isprint(ibuf[isz])) + isz--; + isump = &ibuf[isz-1]; + isum = strtoul(isump, NULL,16); + if (isum != mag_pchecksum(&ibuf[1], isz-3)) { + if (debug_serial) + warning( "RXERR %02x/%02x: '%s'\n", isum, mag_pchecksum(&ibuf[1],isz-5), ibuf); + /* Special case receive errors early on. */ + if (!got_version) { + fatal(MYNAME ": bad communication. Check bit rate.\n"); + } + } + if (debug_serial) { + warning( "READ: %s\n", ibuf); + } + if (IS_TKN("$PMGNCSM,")) { + last_rx_csum = strtoul(&ibuf[9], NULL, 16); + magrxstate = mrs_handon; + return; + } + if (strncmp(ibuf, "$PMGNWPT,", 7) == 0) { + waypoint *wpt = mag_wptparse(ibuf); + waypoint_read_count++; + if (global_opts.verbose_status) { + waypt_status_disp(waypoint_read_count, + waypoint_read_count); + } + switch (global_opts.objective) + { + case wptdata: + waypt_add(wpt); + break; + case rtedata: + ENQUEUE_TAIL(&rte_wpt_tmp, &wpt->Q); + break; + default: + break; + } + } + if (strncmp(ibuf, "$PMGNTRK,", 7) == 0) { + waypoint *wpt = mag_trkparse(ibuf); + /* + * Allow lazy allocation of track head. + */ + if (trk_head == NULL) { + trk_head = route_head_alloc(); + track_add_head(trk_head); + } + + route_add_wpt(trk_head, wpt); + } + if (strncmp(ibuf, "$PMGNRTE,", 7) == 0) { + mag_rteparse(ibuf); + } + if (IS_TKN("$PMGNVER,")) { + mag_verparse(ibuf); + } + mag_error = 0; + if (!ignore_unable && IS_TKN("$PMGNCMD,UNABLE")) { + warning( "Unable to send\n"); + found_done = 1; + mag_error = 1; + ignore_unable = 0; + return; + } + if (IS_TKN("$PMGNCMD,END") || (is_file && (feof(magfile_in)))) { + found_done = 1; + return; + } + if (magrxstate != mrs_handoff) + mag_writeack(isum); +} + +/* + * termio on Cygwin is apparently broken, so we revert to Windows serial. + */ +#if defined (__WIN32__) || defined (__CYGWIN__) + +#include + +DWORD +mkspeed(bitrate) +{ + switch (bitrate) { + case 1200: return CBR_1200; + case 2400: return CBR_2400; + case 4800: return CBR_4800; + case 9600: return CBR_9600; + case 19200: return CBR_19200; + case 57600: return CBR_57600; + case 115200: return CBR_115200; + default: return CBR_4800; + } +} + +HANDLE comport = NULL; + +#define xCloseHandle(a) if (a) { CloseHandle(a); } a = NULL; + +static +int +terminit(const char *portname, int create_ok) +{ + DCB tio; + COMMTIMEOUTS timeout; + + is_file = 0; + + xCloseHandle(comport); + + comport = CreateFile(portname, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, NULL); + + if (comport == INVALID_HANDLE_VALUE) { + goto try_as_file; + } + tio.DCBlength = sizeof(DCB); + GetCommState (comport, &tio); + tio.BaudRate = mkspeed(bitrate); + tio.fBinary = TRUE; + tio.fParity = TRUE; + tio.fOutxCtsFlow = FALSE; + tio.fOutxDsrFlow = FALSE; + tio.fDtrControl = DTR_CONTROL_ENABLE; + tio.fDsrSensitivity = FALSE; + tio.fTXContinueOnXoff = TRUE; + tio.fOutX = FALSE; + tio.fInX = FALSE; + tio.fErrorChar = FALSE; + tio.fNull = FALSE; + tio.fRtsControl = RTS_CONTROL_ENABLE; + tio.fAbortOnError = FALSE; + tio.ByteSize = 8; + tio.Parity = NOPARITY; + tio.StopBits = ONESTOPBIT; + + if (!SetCommState (comport, &tio)) { + xCloseHandle(comport); + + /* + * Probably not a com port. Try it as a file. + */ +try_as_file: + magfile_in = xfopen(portname, create_ok ? "w+b" : "rb", MYNAME); + is_file = 1; + icon_mapping = map330_icon_table; + mag_cleanse = m330_cleanse; + got_version = 1; + return 0; + } + + GetCommTimeouts (comport, &timeout); + /* We basically do single character reads and simulate line input + * mode, so these values are kind of fictional. + */ + timeout.ReadIntervalTimeout = 1000; + timeout.ReadTotalTimeoutMultiplier = 1000; + timeout.ReadTotalTimeoutConstant = 1000; + timeout.WriteTotalTimeoutMultiplier = 1000; + timeout.WriteTotalTimeoutConstant = 1000; + if (!SetCommTimeouts (comport, &timeout)) { + xCloseHandle (comport); + fatal(MYNAME ": set timeouts\n"); + } + return 1; +} + +static char * +termread(char *ibuf, int size) +{ + int i=0; + DWORD cnt; + + if (is_file) { + return fgets(ibuf, size, magfile_in); + } + + ibuf[i]='a'; + for(;i < size;i++) { + if (ReadFile (comport, &ibuf[i], 1, &cnt, NULL) != TRUE) + break; + if (cnt < 1) + return NULL; + if (ibuf[i] == '\n') + break; + } + ibuf[i] = 0; + return ibuf; +} + +static void +termwrite(char *obuf, int size) +{ + DWORD len; + + if (is_file) { + fwrite(obuf, size, 1, magfile_out); + return; + } + WriteFile (comport, obuf, size, &len, NULL); + if (len != size) { + fatal(MYNAME ":. Wrote %d of %d bytes.\n", len, size); + } +} + +static +void +termdeinit() +{ + xCloseHandle(comport); +} + +#else + +#include +#include + +speed_t +mkspeed(unsigned br) +{ + switch (br) { + case 1200: return B1200; + case 2400: return B2400; + case 4800: return B4800; + case 9600: return B9600; + case 19200: return B19200; +#if defined B57600 + case 57600: return B57600; +#endif +#if defined B115200 + case 115200: return B115200; +#endif + default: return B4800; + } +} + + +static struct termios orig_tio; +static void +terminit(const char *portname, int create_ok) +{ + struct termios new_tio; + + magfile_in = xfopen(portname, "rb", MYNAME); + + is_file = !isatty(fileno(magfile_in)); + if (is_file) { + icon_mapping = map330_icon_table; + mag_cleanse = m330_cleanse; + got_version = 1; + return; + } + + magfile_out = xfopen(portname, "w+b", MYNAME); + magfd = fileno(magfile_in); + + tcgetattr(magfd, &orig_tio); + new_tio = orig_tio; + new_tio.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR| + IGNCR|ICRNL|IXON); + new_tio.c_oflag &= ~OPOST; + new_tio.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + new_tio.c_cflag &= ~(CSIZE|PARENB); + new_tio.c_cflag |= CS8; + new_tio.c_cc[VTIME] = 10; + new_tio.c_cc[VMIN] = 0; + + cfsetospeed(&new_tio, mkspeed(bitrate)); + cfsetispeed(&new_tio, mkspeed(bitrate)); + tcsetattr(magfd, TCSAFLUSH, &new_tio); +} + +static void +termdeinit() +{ + if (!is_file) { + tcsetattr(magfd, TCSANOW, &orig_tio); + } +} + +static char * +termread(char *ibuf, int size) +{ + return fgets(ibuf, size, magfile_in); +} + +static void +termwrite(char *obuf, int size) +{ + fwrite(obuf, size, 1, magfile_out); +} +#endif + +/* + * Arg tables are doubled up so that -? can output appropriate help + */ +static +arglist_t mag_sargs[] = { + {"baud", &bs, "Numeric value of bitrate (baud=4800)", NULL, + ARGTYPE_INT }, + {"noack", &noack, "Suppress use of handshaking in name of speed", + NULL, ARGTYPE_BOOL}, + {"deficon", &deficon, "Default icon name", NULL, ARGTYPE_STRING }, + {"nukewpt", &nukewpt, "Delete all waypoints", NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + +static +arglist_t mag_fargs[] = { + {"deficon", &deficon, "Default icon name", NULL, ARGTYPE_STRING }, + {0, 0, 0, 0, 0} +}; + +static void +mag_rd_init(const char *portname) +{ + time_t now, later; + waypoint_read_count = 0; + + if (bs) { + bitrate=atoi(bs); + } + + terminit(portname, 0); + if (!mkshort_handle) { + mkshort_handle = mkshort_new_handle(); + } + + if (!noack) + mag_handon(); + + now = current_time(); + /* + * The 315 can take up to 4.25 seconds to respond to initialization + * commands. Time out on the side of caution. + */ + later = now + 6; + if (!is_file) { + got_version = 0; + mag_writemsg("PMGNCMD,VERSION"); + } + + while (!got_version) { + mag_readmsg(); + if (current_time() > later) { + fatal(MYNAME ": No acknowledgment from GPS on %s\n", + portname); + } + } + + if (!is_file && (icon_mapping != gps315_icon_table)) { + /* + * The 315 can't handle this command, so we set a global + * to ignore the NAK on it. + */ + ignore_unable = 1; + mag_writemsg("PMGNCMD,NMEAOFF"); + ignore_unable = 0; + } + if (nukewpt) { + /* The unit will send us an "end" message upon completion */ + mag_writemsg("PMGNCMD,DELETE,WAYPOINT"); + mag_readmsg(); + if (!found_done) { + fatal(MYNAME ": Unexpected response to waypoint delete command.\n"); + } + found_done = 0; + } + + QUEUE_INIT(&rte_wpt_tmp); + + return; +} + +static void +mag_wr_init(const char *portname) +{ +#if __WIN32__ + if (!terminit(portname, 1)) { + is_file = 1; + } +#else + magfile_out = xfopen(portname, "w+b", MYNAME); + is_file = !isatty(fileno(magfile_out)); +#endif + + if (!mkshort_handle) { + mkshort_handle = mkshort_new_handle(); + } + if (is_file) { + magfile_out = xfopen(portname, "w+b", MYNAME); + icon_mapping = map330_icon_table; + mag_cleanse = m330_cleanse; + got_version = 1; + } else { + /* + * This is a serial device. The line has to be open for + * reading and writing, so we let rd_init do the dirty work. + */ + if (magfile_out) { + fclose(magfile_out); + } +#if __WIN32__ + if (comport) { + xCloseHandle(comport); + } +#endif + mag_rd_init(portname); + } + QUEUE_INIT(&rte_wpt_tmp); +} + +static void +mag_deinit(void) +{ + mag_handoff(); + termdeinit(); + if(magfile_in) + fclose(magfile_in); + magfile_in = NULL; + if(mkshort_handle) + mkshort_del_handle(mkshort_handle); + mkshort_handle = NULL; + + waypt_flush(&rte_wpt_tmp); +} + + +/* + * Given an incoming track messages of the form: + * $PMGNTRK,3605.259,N,08644.389,W,00151,M,201444.61,A,,020302*66 + * create and return a populated waypoint. + */ +waypoint * +mag_trkparse(char *trkmsg) +{ + double latdeg, lngdeg; + int alt; + char altunits; + char lngdir, latdir; + int dmy; + int hms; + int fracsecs; + struct tm tm; + waypoint *waypt; + + waypt = xcalloc(sizeof *waypt, 1); + + memset(&tm, 0, sizeof(tm)); + + sscanf(trkmsg,"$PMGNTRK,%lf,%c,%lf,%c,%d,%c,%d.%d,A,,%d", + &latdeg,&latdir, + &lngdeg,&lngdir, + &alt,&altunits,&hms,&fracsecs,&dmy); + + tm.tm_sec = hms % 100; + hms = hms / 100; + tm.tm_min = hms % 100; + hms = hms / 100; + tm.tm_hour = hms % 100; + + tm.tm_year = 100 + dmy % 100; + dmy = dmy / 100; + tm.tm_mon = dmy % 100 - 1; + dmy = dmy / 100; + tm.tm_mday = dmy % 100; + + waypt->creation_time = mktime(&tm) + get_tz_offset(); + waypt->centiseconds = fracsecs; + + if (latdir == 'S') latdeg = -latdeg; + waypt->latitude = ddmm2degrees(latdeg); + + if (lngdir == 'W') lngdeg = -lngdeg; + waypt->longitude = ddmm2degrees(lngdeg); + + waypt->altitude = alt; + + return waypt; + +} + +/* + * Given an incoming route messages of the form: + * $PMGNRTE,4,1,c,1,DAD,a,Anna,a*61 + * generate a route. + */ +void +mag_rteparse(char *rtemsg) +{ + char descr[100]; + int n; + int frags,frag,rtenum; + char xbuf[100],next_stop[100],abuf[100]; + char *currtemsg; + static mag_rte_head *mag_rte_head; + mag_rte_elem *rte_elem; + char *p; + + descr[0] = 0; + + sscanf(rtemsg,"$PMGNRTE,%d,%d,%c,%d%n", + &frags,&frag,xbuf,&rtenum,&n); + + /* + * This is the first component of a route. Allocate a new + * queue head. + */ + if (frag == 1) { + mag_rte_head = xcalloc(sizeof (*mag_rte_head),1); + QUEUE_INIT(&mag_rte_head->Q); + mag_rte_head->nelems = frags; + } + + currtemsg = rtemsg + n; + + /* + * The individual line may contain several route elements. + * loop and pick those up. + */ + while (sscanf(currtemsg,",%[^,],%[^,]%n",next_stop, abuf,&n)) { + if ((next_stop[0] == 0) || (next_stop[0] == '*')) { + break; + } + + /* trim CRC from waypoint icon string */ + if ((p = strchr(abuf, '*')) != NULL) + *p = '\0'; + + rte_elem = xcalloc(sizeof (*rte_elem),1); + QUEUE_INIT(&rte_elem->Q); + + rte_elem->wpt_name = xstrdup(next_stop); + rte_elem->wpt_icon = xstrdup(abuf); + + ENQUEUE_TAIL(&mag_rte_head->Q, &rte_elem->Q); + next_stop[0] = 0; + currtemsg += n; + } + + /* + * If this was the last fragment of the route, add it to the + * gpsbabel internal structs now. + */ + if (frag == mag_rte_head->nelems) { + queue *elem, *tmp; + route_head *rte_head; + + rte_head = route_head_alloc(); + route_add_head(rte_head); + rte_head->rte_num = rtenum; + + /* + * It is quite feasible that we have 200 waypoints, + * 3 of which are used in the route. We'll need to find + * those in the queue for SD routes... + */ + + QUEUE_FOR_EACH(&mag_rte_head->Q, elem, tmp) { + mag_rte_elem *re = (mag_rte_elem *) elem; + waypoint *waypt; + queue *welem, *wtmp; + + /* + * Copy route points from temp wpt queue. + */ + QUEUE_FOR_EACH(&rte_wpt_tmp, welem, wtmp) { + waypt = (waypoint *)welem; + if (strcmp(waypt->shortname, re->wpt_name) == 0) { + waypoint * wpt = waypt_dupe(waypt); + route_add_wpt(rte_head, wpt); + break; + } + } + + dequeue(&re->Q); + xfree(re->wpt_name); + xfree(re->wpt_icon); + xfree(re); + } + xfree(mag_rte_head); + } +} + +const char * +mag_find_descr_from_token(const char *token) +{ + icon_mapping_t *i = icon_mapping; + + if (icon_mapping == NULL) { + return "unknown"; + } + + for (i = icon_mapping; i->token; i++) { + if (case_ignore_strcmp(token, i->token) == 0) + return i->icon; + } + return icon_mapping[0].icon; +} + +const char * +mag_find_token_from_descr(const char *icon) +{ + icon_mapping_t *i = icon_mapping; + + if (i == NULL || icon == NULL) { + return "a"; + } + + for (i = icon_mapping; i->token; i++) { + if (case_ignore_strcmp(icon, i->icon) == 0) + return i->token; + } + return icon_mapping[0].token; +} + +/* + * Given an incoming waypoint messages of the form: + * $PMGNWPL,3549.499,N,08650.827,W,0000257,M,HOME,HOME,c*4D + * create and return a populated waypoint. + */ +static waypoint * +mag_wptparse(char *trkmsg) +{ + double latdeg, lngdeg; + char latdir; + char lngdir; + int alt; + char altunits; + char shortname[100]; + char descr[100]; + char icon_token[100]; + waypoint *waypt; + char *icons; + char *icone; + char *blah; + int i = 0; + + descr[0] = 0; + icon_token[0] = 0; + + waypt = xcalloc(sizeof *waypt, 1); + + sscanf(trkmsg,"$PMGNWPL,%lf,%c,%lf,%c,%d,%c,%[^,],%[^,]", + &latdeg,&latdir, + &lngdeg,&lngdir, + &alt,&altunits,shortname,descr); + icone = strrchr(trkmsg, '*'); + icons = strrchr(trkmsg, ',')+1; + + for (blah = icons ; blah < icone; blah++) + icon_token[i++] = *blah; + icon_token[i++] = '\0'; + + if (latdir == 'S') latdeg = -latdeg; + waypt->latitude = ddmm2degrees(latdeg); + + if (lngdir == 'W') lngdeg = -lngdeg; + waypt->longitude = ddmm2degrees(lngdeg); + + waypt->altitude = alt; + waypt->shortname = xstrdup(shortname); + waypt->description = xstrdup(descr); + waypt->icon_descr = mag_find_descr_from_token(icon_token); + + return waypt; +} + +static void +mag_read(void) +{ + found_done = 0; + + switch (global_opts.objective) + { + case trkdata: + if (!is_file) + mag_writemsg("PMGNCMD,TRACK,2"); + + while (!found_done) { + mag_readmsg(); + } + + break; + case wptdata: + if (!is_file) + mag_writemsg("PMGNCMD,WAYPOINT"); + + while (!found_done) { + mag_readmsg(); + } + + break; + case rtedata: + if (!is_file) { + /* + * serial routes require waypoint & routes + * messages commands. + */ + mag_writemsg("PMGNCMD,WAYPOINT"); + + while (!found_done) { + mag_readmsg(); + } + + mag_writemsg("PMGNCMD,ROUTE"); + + found_done = 0; + while (!found_done) { + mag_readmsg(); + } + } else { + /* + * SD routes are a stream of PMGNWPL and + * PMGNRTE messages, in that order. + */ + while (!found_done) { + mag_readmsg(); + } + } + + break; + default: + fatal(MYNAME ": Unknown objective\n"); + } +} + +static +void +mag_waypt_pr(const waypoint *waypointp) +{ + double lon, lat; + double ilon, ilat; + int lon_deg, lat_deg; + char obuf[200]; + char ofmtdesc[200]; + const char *icon_token=NULL; + char *owpt; + char *odesc; + char *isrc; + + ilat = waypointp->latitude; + ilon = waypointp->longitude; + + lon = fabs(ilon); + lat = fabs(ilat); + + lon_deg = lon; + lat_deg = lat; + + lon = (lon - lon_deg) * 60.0; + lat = (lat - lat_deg) * 60.0; + + lon = (lon_deg * 100.0 + lon); + lat = (lat_deg * 100.0 + lat); + + if (deficon) { + icon_token = mag_find_token_from_descr(deficon); + } else { + icon_token = mag_find_token_from_descr(waypointp->icon_descr); + } + + if (get_cache_icon(waypointp)) { + icon_token = mag_find_token_from_descr(get_cache_icon(waypointp)); + } + + isrc = waypointp->notes ? waypointp->notes : waypointp->description; + owpt = global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, isrc) : waypointp->shortname; + odesc = isrc ? isrc : ""; + owpt = mag_cleanse(owpt); + + if (waypointp->gc_data.diff && waypointp->gc_data.terr) { + sprintf(ofmtdesc, "%d/%d %s", waypointp->gc_data.diff, + waypointp->gc_data.terr, odesc); + odesc = mag_cleanse(ofmtdesc); + } else { + odesc = mag_cleanse(odesc); + } + + sprintf(obuf, "PMGNWPL,%4.3f,%c,%09.3f,%c,%07.lf,M,%-.8s,%-.30s,%s", + lat, ilat < 0 ? 'S' : 'N', + lon, ilon < 0 ? 'W' : 'E', + waypointp->altitude == unknown_alt ? + 0 : waypointp->altitude, + owpt, + odesc, + icon_token); + mag_writemsg(obuf); + xfree(owpt); + xfree(odesc); + + if (!is_file) { + if (mag_error) { + warning( "Protocol error Writing '%s'\n", obuf); + } + } +} + +static +void mag_track_nop(const route_head *rte) +{ + return; +} + +static +void mag_track_disp(const waypoint *waypointp) +{ + double ilon, ilat; + double lon, lat; + int lon_deg, lat_deg; + char obuf[200]; + int hms=0; + int fracsec=0; + int date=0; + struct tm *tm = NULL; + + ilat = waypointp->latitude; + ilon = waypointp->longitude; + tm = NULL; + if (waypointp->creation_time) { + tm = gmtime(&waypointp->creation_time); + if ( tm ) { + hms = tm->tm_hour * 10000 + tm->tm_min * 100 + + tm->tm_sec; + date = tm->tm_mday * 10000 + tm->tm_mon * 100 + + tm->tm_year; + fracsec = waypointp->centiseconds; + } + } + if (!tm) { + date = 0; + fracsec = 0; + } + + lon = fabs(ilon); + lat = fabs(ilat); + + lon_deg = lon; + lat_deg = lat; + + lon = (lon - lon_deg) * 60.0; + lat = (lat - lat_deg) * 60.0; + + lon = (lon_deg * 100.0 + lon); + lat = (lat_deg * 100.0 + lat); + + sprintf(obuf,"PMGNTRK,%4.3f,%c,%09.3f,%c,%05.f,%c,%06d.%02d,A,,%06d", + lat, ilat < 0 ? 'S' : 'N', + lon, ilon < 0 ? 'W' : 'E', + waypointp->altitude == unknown_alt ? + 0 : waypointp->altitude, + 'M',hms,fracsec,date); + mag_writemsg(obuf); +} + +static +void mag_track_pr() +{ + track_disp_all(mag_track_nop, mag_track_nop, mag_track_disp); +} + +/* +The spec says to stack points: + $PMGNRTE,2,1,c,1,FOO,POINT1,b,POINT2,c,POINT3,d*6C + +Meridian SD card and serial (at least) writes in pairs: + $PMGNRTE,4,1,c,1,HOME,c,I49X73,a*15 + ... + $PMGNRTE,4,4,c,1,RON273,a,MYCF93,a*7B + +The spec also says that some units don't like single-legged pairs, +and to replace the 2nd name with "<<>>", but I haven't seen one of those. +*/ + +static void +mag_route_trl(const route_head * rte) +{ + queue *elem, *tmp; + waypoint *waypointp; + char obuff[256]; + char buff1[64], buff2[64]; + char *pbuff, *owpt; + const char * icon_token; + int i, numlines, thisline; + + /* count waypoints for this route */ + i = rte->rte_waypt_ct; + + /* number of output PMGNRTE messages at 2 points per line */ + numlines = (i / 2) + (i % 2); + + /* increment the route counter. */ + route_out_count++; + + thisline = i = 0; + QUEUE_FOR_EACH(&rte->waypoint_list, elem, tmp) { + waypointp = (waypoint *) elem; + i++; + + if (deficon) + icon_token = mag_find_token_from_descr(deficon); + else + icon_token = mag_find_token_from_descr(waypointp->icon_descr); + + if (i == 1) + pbuff = buff1; + else + pbuff = buff2; + + owpt = waypointp->shortname; + owpt = mag_cleanse(owpt); + + sprintf(pbuff, "%s,%s", owpt, icon_token); + + xfree(owpt); + + if ((tmp == &rte->waypoint_list) || ((i % 2) == 0)) { + thisline++; + + sprintf(obuff, "PMGNRTE,%d,%d,c,%d,%s,%s", + numlines, thisline, route_out_count, + buff1, buff2); + + mag_writemsg(obuff); + buff1[0] = '\0'; + buff2[0] = '\0'; + i = 0; + } + } +} + +static void +mag_route_hdr(const route_head *rh) +{ +} + +static void +mag_route_pr() +{ + route_out_count = 0; + route_disp_all(mag_route_hdr, mag_route_trl, mag_waypt_pr); + +} + +static void +mag_write(void) +{ + /* + * Whitespace is actually legal, but since waypoint name length is + * only 8 bytes, we'll conserve them. + */ + setshort_whitespace_ok(mkshort_handle, 0); + switch (global_opts.objective) + { + case trkdata: + mag_track_pr(); + break; + case wptdata: + waypt_disp_all(mag_waypt_pr); + break; + case rtedata: + mag_route_pr(); + break; + default: + fatal(MYNAME ": Unknown objective.\n"); + } +} + +/* + * This is repeated just so it shows up as separate menu options + * for the benefit of GUI wrappers. + */ +ff_vecs_t mag_svecs = { + ff_type_serial, + mag_rd_init, + mag_wr_init, + mag_deinit, + mag_deinit, + mag_read, + mag_write, + NULL, + mag_sargs +}; + +ff_vecs_t mag_fvecs = { + ff_type_file, + mag_rd_init, + mag_wr_init, + mag_deinit, + mag_deinit, + mag_read, + mag_write, + NULL, + mag_fargs +}; diff --git a/main.c b/main.c new file mode 100644 index 000000000..78acd8dfe --- /dev/null +++ b/main.c @@ -0,0 +1,300 @@ +/* + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + + +#include "defs.h" +#include + +global_options global_opts; +const char gpsbabel_version[] = VERSION; + +static void +usage(const char *pname, int shorter) +{ + printf("GPSBabel Version %s. http://www.gpsbabel.org\n\n", + VERSION ); + printf( +"Usage:\n" +" %s [options] -i INTYPE -f INFILE -o OUTTYPE -F OUTFILE\n" +" %s [options] -i INTYPE -o OUTTYPE INFILE [OUTFILE]\n" +"\n" +" Converts GPS route and waypoint data from one format type to another.\n" +" The input type and filename are specified with the -i INTYPE\n" +" and -f INFILE options. The output type and filename are specified\n" +" with the -o OUTTYPE and -F OUTFILE options.\n" +"\n" +" In the second form of the command, INFILE and OUTFILE are the\n" +" first and second positional (non-option) arguments.\n" +"\n" +" INTYPE and OUTTYPE must be one of the file types listed below, and\n" +" may include options valid for that file type. For example:\n" +" 'gpx', 'gpx,snlen=10' and 'ozi,snlen=10,snwhite=1'\n" +" (without the quotes) are all valid file type specifications.\n" +"\n" +"Options:\n" +" -s Synthesize shortnames\n" +" -r Process route information\n" +" -t Process track information\n" +" -w Process waypoint information [default]\n" +" -N No smart icons on output\n" +" -x filtername Invoke filter\n" +" -D level Set debug level [%d]\n" +" -h, -? Print detailed help and exit\n" +" -V Print GPSBabel version and exit\n" +"\n" + , pname + , pname + , global_opts.debug_level + ); + if ( shorter ) { + printf( "\n\n[Press enter]" ); + fgetc(stdin); + } + else { + printf("File Types (-i and -o options):\n"); + disp_vecs(); + printf("\nSupported data filters:\n"); + disp_filter_vecs(); + } +} + + + +int +main(int argc, char *argv[]) +{ + int c; + int argn; + ff_vecs_t *ivecs = NULL; + ff_vecs_t *ovecs = NULL; + filter_vecs_t *fvecs = NULL; + char *fname = NULL; + char *ofname = NULL; + char *ivec_opts = NULL; + char *ovec_opts = NULL; + char *fvec_opts = NULL; + int opt_version = 0; + int did_something = 0; + const char *prog_name = argv[0]; /* argv is modified during processing */ + + global_opts.objective = wptdata; + global_opts.masked_objective = NOTHINGMASK; /* this makes the default mask behaviour slightly different */ + +#ifdef DEBUG_MEM + debug_mem_open(); + debug_mem_output( "command line: " ); + for ( argn = 1; argn < argc; argn++ ) { + debug_mem_output( "%s ", argv[argn] ); + } + debug_mem_output( "\n" ); +#endif + + waypt_init(); + route_init(); + + if ( argc < 2 ) { + usage(argv[0],1); + exit(0); + } + + /* + * Open-code getopts since POSIX-impaired OSes don't have one. + */ + for (argn = 1; argn < argc; argn++) { + char *optarg; + + if (argv[argn][0] != '-') { + break; + } + if (argv[argn][1] == '-') { + break; + } + + if (argv[argn][1] == 'V' ) { + printf("\nGPSBabel Version %s\n\n", VERSION ); + exit(0); + } + + if (argv[argn][1] == '?' || argv[argn][1] == 'h') { + usage(argv[0],0); + exit(0); + } + + c = argv[argn][1]; + + if (argv[argn][2]) { + opt_version = atoi(&argv[argn][2]); + } + + switch (c) { + case 'i': + optarg = argv[argn][2] + ? argv[argn]+2 : argv[++argn]; + ivecs = find_vec(optarg, &ivec_opts); + break; + case 'o': + optarg = argv[argn][2] + ? argv[argn]+2 : argv[++argn]; + ovecs = find_vec(optarg, &ovec_opts); + break; + case 'f': + optarg = argv[argn][2] + ? argv[argn]+2 : argv[++argn]; + fname = optarg; + if (ivecs == NULL) { + fatal ("No valid input type specified\n"); + } + if (ivecs->rd_init == NULL) { + fatal ("Format does not support reading.\n"); + } + /* simulates the default behaviour of waypoints */ + if (doing_nothing) global_opts.masked_objective |= WPTDATAMASK; + ivecs->rd_init(fname); + ivecs->read(); + ivecs->rd_deinit(); + did_something = 1; + break; + case 'F': + optarg = argv[argn][2] + ? argv[argn]+2 : argv[++argn]; + ofname = optarg; + if (ovecs) { + /* simulates the default behaviour of waypoints */ + if (doing_nothing) + global_opts.masked_objective |= WPTDATAMASK; + if (ovecs->wr_init == NULL) { + fatal ("Format does not support writing.\n"); + } + ovecs->wr_init(ofname); + ovecs->write(); + ovecs->wr_deinit(); + } + break; + case 's': + global_opts.synthesize_shortnames = 1; + break; + case 't': + global_opts.objective = trkdata; + global_opts.masked_objective |= TRKDATAMASK; + break; + case 'w': + global_opts.objective = wptdata; + global_opts.masked_objective |= WPTDATAMASK; + break; + case 'r': + global_opts.objective = rtedata; + global_opts.masked_objective |= RTEDATAMASK; + break; + case 'N': + global_opts.no_smart_icons = 1; + break; + case 'x': + optarg = argv[argn][2] + ? argv[argn]+2 : argv[++argn]; + fvecs = find_filter_vec(optarg, &fvec_opts); + + if (fvecs) { + if (fvecs->f_init) fvecs->f_init(fvec_opts); + fvecs->f_process(); + if (fvecs->f_deinit) fvecs->f_deinit(); + free_filter_vec(fvecs); + } else { + fatal("Unknown filter '%s'\n",optarg); + } + break; + case 'D': + optarg = argv[argn][2] + ? argv[argn]+2 : argv[++argn]; + global_opts.debug_level = atoi(optarg); + /* + * When debugging, announce version. + */ + if (global_opts.debug_level > 0) { + warning("GPSBabel Version: " VERSION "\n" ); + } + + break; + /* + * Undocumented '-vs' option for GUI wrappers. + */ + case 'v': + switch(argv[argn][2]) { + case 's': global_opts.verbose_status = 1; break; + } + break; + + /* + * DOS-derived systems will need to escape + * this as -^^. + */ + case '^': + disp_formats(opt_version); + exit(0); + case '%': + disp_filters(opt_version); + exit(0); + case 'h': + case '?': + usage(argv[0],0); + exit(0); + } + } + + /* + * Allow input and output files to be specified positionally + * as well. This is the typical command line format. + */ + argc -= argn; + argv += argn; + if (argc > 2) { + fatal ("Extra arguments on command line\n"); + } + else if (argc && ivecs) { + did_something = 1; + /* simulates the default behaviour of waypoints */ + if (doing_nothing) global_opts.masked_objective |= WPTDATAMASK; + ivecs->rd_init(argv[0]); + ivecs->read(); + ivecs->rd_deinit(); + if (argc == 2 && ovecs) { + ovecs->wr_init(argv[1]); + ovecs->write(); + ovecs->wr_deinit(); + } + } + else if (argc) { + usage(prog_name,0); + exit(0); + } + if (ovecs == NULL) + waypt_disp_all(waypt_disp); + + if (!did_something) + fatal ("Nothing to do! Use '%s -h' for command-line options.\n", prog_name); + + waypt_flush_all(); + route_flush_all(); + exit_vecs(); + exit_filter_vecs(); + +#ifdef DEBUG_MEM + debug_mem_close(); +#endif + exit(0); +} diff --git a/mapopolis.c b/mapopolis.c new file mode 100644 index 000000000..fecb23f87 --- /dev/null +++ b/mapopolis.c @@ -0,0 +1,320 @@ +/* + Read and write Mapopolis files. + + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "coldsync/palm.h" +#include "coldsync/pdb.h" + +#define MYNAME "Companion Waypoints" +#define MYTYPE 0x64617461 /* Platdata */ +#define MYCREATOR 0x5061746c /* Plat */ + +#define LONDIV (85116.044444) +#define LATDIV (1000000.0/9) +#define LONDIV2 (85116.044444/2) +#define LATDIV2 (1000000.0/(9*2)) + + +struct record0 +{ + char unk[6]; + pdb_32 lon1; + pdb_32 lat1; + pdb_32 lon2; + pdb_32 lat2; + pdb_32 lonD; + pdb_32 latD; + char name[31+1]; + char unk2[35]; + char demo; + char unk3[4]; + unsigned char expcode[4]; + /* ... more stuff ... */ +}; + +double Lat1, Lon1; +double Lat2, Lon2; +double LatD, LonD; + +struct record { + char unknown[10]; + pdb_16 unk1; + pdb_16 unk2; + pdb_16 lon1d; + pdb_16 lat1d; + pdb_16 lon2d; + pdb_16 lat2d; +}; + +static FILE *file_in; +static FILE *file_out; +static const char *out_fname; +static void *mkshort_handle; + +struct pdb *opdb; +struct pdb_record *opdb_rec; + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "rb", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "wb", MYNAME); + out_fname = fname; + mkshort_handle = mkshort_new_handle(); + setshort_length(mkshort_handle, 20); +} + +static void +wr_deinit(void) +{ + fclose(file_out); + mkshort_del_handle(mkshort_handle); +} + +convert_rec0(struct record0 *rec0) +{ + Lon1 = be_read32(&rec0->lon1) / LONDIV; + Lat1 = be_read32(&rec0->lat1) / LATDIV; + Lon2 = be_read32(&rec0->lon2) / LONDIV; + Lat2 = be_read32(&rec0->lat2) / LATDIV; + LonD = be_read32(&rec0->lonD) / LONDIV2; + LatD = be_read32(&rec0->latD) / LATDIV2; + +// printf("%s: %.5f %.5f %.5f %.5f %.5f %.5f\n", +// rec0->name, Lat1, Lon1, Lat2, Lon2, LatD, LonD); + + +} + +/* + * * Decode the information field + * */ +void +decode(char *buf) +{ + int i; + + for (i = 0; buf[i]; ++i) { + buf[i] = buf[i] ^ ((i % 96) & 0xf); + } +} + + static void + data_read(void) +{ + struct record *rec; + struct pdb *pdb; + struct pdb_record *pdb_rec; + + if (NULL == (pdb = pdb_Read(fileno(file_in)))) { + fatal(MYNAME ": pdb_Read failed\n"); + } + + if ((pdb->creator != MYCREATOR) || (pdb->type != MYTYPE)) { + fatal(MYNAME ": Not a Magellan Navigator file.\n"); + } + + pdb_rec = pdb->rec_index.rec; + convert_rec0((struct record0*) pdb_rec->data); + +// for(pdb_rec = pdb->rec_index.rec; pdb_rec; pdb_rec=pdb_rec->next) { + for(pdb_rec=pdb_rec->next; pdb_rec; pdb_rec=pdb_rec->next) { + waypoint *wpt_tmp; + char *vdata; + char *edata; + struct tm tm = {0}; + + rec = (struct record *) pdb_rec->data; + edata = (char *) rec + pdb_rec->data_len; + + for (; vdata < edata; rec = (struct record *) vdata) { + wpt_tmp = xcalloc(sizeof(*wpt_tmp),1); + wpt_tmp->latitude = Lat1 + + be_read16(&rec->lat1d) / LATDIV2; + wpt_tmp->longitude = Lon1 + + be_read16(&rec->lon1d) / LONDIV2; + + vdata = (char *) rec + sizeof(*rec); + wpt_tmp->description = strdup(vdata); + vdata += strlen(wpt_tmp->description) + 1 + 6; + + while (*vdata == 0x40) + vdata++; + decode(vdata); + wpt_tmp->notes = strdup(vdata); + vdata += strlen(wpt_tmp->notes) + 1; + + waypt_add(wpt_tmp); + } + } + free_pdb(pdb); +} + + +static void +my_writewpt(const waypoint *wpt) +{ +#if 0 + struct record *rec; + static int ct; + struct tm *tm; + char *vdata; + time_t tm_t; + const char *sn = global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, wpt->description) : + wpt->shortname; + + rec = xcalloc(sizeof(*rec)+56,1); + + tm = NULL; + if ( wpt->creation_time ) { + tm = gmtime( &wpt->creation_time); + } + if ( !tm ) { + tm_t = current_time(); + tm = gmtime( &tm_t ); + } + + be_write16( &rec->crt_sec, tm->tm_sec ); + be_write16( &rec->crt_min, tm->tm_min ); + be_write16( &rec->crt_hour, tm->tm_hour ); + be_write16( &rec->crt_mday, tm->tm_mday ); + be_write16( &rec->crt_mon, tm->tm_mon + 1 ); + be_write16( &rec->crt_year, tm->tm_mon + 1900 ); + + be_write16( &rec->unknown, 0); + + be_write16( &rec->xx_sec, tm->tm_sec ); + be_write16( &rec->xx_min, tm->tm_min ); + be_write16( &rec->xx_hour, tm->tm_hour ); + be_write16( &rec->xx_mday, tm->tm_mday ); + be_write16( &rec->xx_mon, tm->tm_mon + 1 ); + be_write16( &rec->xx_year, tm->tm_mon + 1900 ); + + be_write16( &rec->unknown2, 0); + + be_write32(&rec->longitude, si_round(wpt->longitude * 100000.0)); + be_write32(&rec->latitude, si_round(wpt->latitude * 100000.0)); + be_write32(&rec->elevation, wpt->altitude); + + rec->plot = 0; + rec->unknown3 = 'a'; + + vdata = (char *)rec + sizeof(*rec); + if ( sn ) { + strncpy( vdata, sn, 21 ); + vdata[20] = '\0'; + } + else { + vdata[0] ='\0'; + } + vdata += strlen( vdata ) + 1; + if ( wpt->description ) { + strncpy( vdata, wpt->description, 33 ); + vdata[32] = '\0'; + } + else { + vdata[0] = '\0'; + } + vdata += strlen( vdata ) + 1; + vdata[0] = '\0'; + vdata[1] = '\0'; + vdata += 2; + + opdb_rec = new_Record (0, 0, ct++, vdata-(char *)rec, (const ubyte *)rec); + + if (opdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create record\n"); + } + + if (pdb_AppendRecord(opdb, opdb_rec)) { + fatal(MYNAME ": libpdb couldn't append record\n"); + } + xfree(rec); +#endif +} + +static void +data_write(void) +{ + queue *elem, *tmp; + + static char *appinfo = + "\0\x01" + "User\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\0\0"; + + if (NULL == (opdb = new_pdb())) { + fatal (MYNAME ": new_pdb failed\n"); + } + + strncpy(opdb->name, "Companion Waypoints", PDB_DBNAMELEN); + opdb->name[PDB_DBNAMELEN-1] = 0; + opdb->attributes = PDB_ATTR_BACKUP; + opdb->ctime = opdb->mtime = current_time() + 2082844800U; + opdb->type = MYTYPE; /* CWpt */ + opdb->creator = MYCREATOR; /* cGPS */ + opdb->version = 1; + opdb->appinfo = (void *)appinfo; + opdb->appinfo_len = 276; + + waypt_disp_all(my_writewpt); + + pdb_Write(opdb, fileno(file_out)); +} + + +ff_vecs_t mapopolis_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, +}; diff --git a/mapsend.c b/mapsend.c new file mode 100644 index 000000000..7477a043f --- /dev/null +++ b/mapsend.c @@ -0,0 +1,594 @@ +/* + Access Magellan Mapsend files. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + */ + +#include +#include + +#include "defs.h" +#include "mapsend.h" +#include "magellan.h" + +static FILE *mapsend_file_in; +static FILE *mapsend_file_out; +static void *mkshort_handle; + +static int route_wp_count; +static int mapsend_infile_version; +static int trk_version = 30; + +#define MYNAME "mapsend" + +static void +mapsend_rd_init(const char *fname) +{ + mapsend_file_in = xfopen(fname, "rb", MYNAME); +} + +static void +mapsend_rd_deinit(void) +{ + fclose(mapsend_file_in); +} + +static +void +my_fread8(void *ptr, FILE *stream) +{ + unsigned char cbuf[8]; + size_t rv; + + rv = fread(cbuf, 8, 1, stream); + le_read64(ptr, cbuf); + +} + +static +void +my_fwrite8(void *ptr, FILE *stream) +{ + unsigned char cbuf[8]; + + le_read64(cbuf, ptr); + fwrite(cbuf, 8, 1, stream); +} + +static +void +my_fread4(void *ptr, FILE *stream) +{ + unsigned int *iptr = ptr; + unsigned char cbuf[4]; + size_t rv; + + rv = fread(cbuf, 4, 1, stream); + *iptr = le_read32(cbuf); +} + +static +size_t +my_fwrite4(int *ptr, FILE *stream) +{ + int i = le_read32(ptr); + return fwrite(&i, 4, 1, stream); +} + +static void +mapsend_wr_init(const char *fname) +{ + mapsend_file_out = xfopen(fname, "wb", MYNAME); + mkshort_handle = mkshort_new_handle(); + route_wp_count = 0; +} + +static void +mapsend_wr_deinit(void) +{ + fclose(mapsend_file_out); + mkshort_del_handle(mkshort_handle); +} + +static void +mapsend_wpt_read(void) +{ + char tbuf[256]; + char name[257]; + char comment[257]; + char *p; + int wpt_count, rte_count, rte_num; + unsigned char scount; + int wpt_number; + char wpt_icon; + char wpt_status; + double wpt_alt; + double wpt_long; + double wpt_lat; + waypoint *wpt_tmp; + route_head *rte_head; + + my_fread4(&wpt_count, mapsend_file_in); + + while (wpt_count--) { + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + + if (fread(&scount, sizeof(scount), 1, mapsend_file_in) < 1) { + fatal(MYNAME ": out of data reading %d waypoints\n", + wpt_count); + } + fread(tbuf, scount, 1, mapsend_file_in); + p = strncpy(name, tbuf, scount); + p[scount] = '\0'; + + fread(&scount, sizeof(scount), 1, mapsend_file_in); + fread(tbuf, scount, 1, mapsend_file_in); + p = strncpy(comment, tbuf, scount); + p[scount] = '\0'; + + my_fread4(&wpt_number, mapsend_file_in); + fread(&wpt_icon, sizeof(wpt_icon), 1, mapsend_file_in); + fread(&wpt_status, sizeof(wpt_status), 1, mapsend_file_in); + my_fread8(&wpt_alt, mapsend_file_in); + my_fread8(&wpt_long, mapsend_file_in); + my_fread8(&wpt_lat, mapsend_file_in); + + wpt_tmp->shortname = xstrdup(name); + wpt_tmp->description = xstrdup(comment); + wpt_tmp->altitude = wpt_alt; + wpt_tmp->latitude = -wpt_lat; + wpt_tmp->longitude = wpt_long; + + if (wpt_icon < 26) + sprintf(tbuf, "%c", wpt_icon + 'a'); + else + sprintf(tbuf, "a%c", wpt_icon - 26 + 'a'); + wpt_tmp->icon_descr = mag_find_descr_from_token(tbuf); + + waypt_add(wpt_tmp); + } + + /* now read the routes... */ + my_fread4(&rte_count, mapsend_file_in); + + while (rte_count--) { + rte_head = route_head_alloc(); + route_add_head(rte_head); + + /* route name */ + fread(&scount, sizeof(scount), 1, mapsend_file_in); + fread(tbuf, scount, 1, mapsend_file_in); + tbuf[scount] = '\0'; + rte_head->rte_name = xstrdup(tbuf); + + /* route # */ + my_fread4(&rte_num, mapsend_file_in); + rte_head->rte_num = rte_num; + + /* points this route */ + my_fread4(&wpt_count, mapsend_file_in); + + while (wpt_count--) { + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + + /* waypoint name */ + fread(&scount, sizeof(scount), 1, mapsend_file_in); + fread(tbuf, scount, 1, mapsend_file_in); + tbuf[scount] = '\0'; + + wpt_tmp->shortname = xstrdup(tbuf); + + /* waypoint # */ + my_fread4(&wpt_number, mapsend_file_in); + my_fread8(&wpt_long, mapsend_file_in); + my_fread8(&wpt_lat, mapsend_file_in); + fread(&wpt_icon, sizeof(wpt_icon), 1, mapsend_file_in); + + wpt_tmp->longitude = wpt_long; + wpt_tmp->latitude = -wpt_lat; + + if (wpt_icon < 26) + sprintf(tbuf, "%c", wpt_icon + 'a'); + else + sprintf(tbuf, "a%c", wpt_icon - 26 + 'a'); + wpt_tmp->icon_descr = mag_find_descr_from_token(tbuf); + + route_add_wpt(rte_head, wpt_tmp); + } + } +} + +static void +mapsend_track_read(void) +{ + char *trk_name; + unsigned char scount; + unsigned int trk_count; + double wpt_long; + double wpt_lat; + double wpt_alt; + int i = 0; + float f = 0; + int time; + int valid; + unsigned char centisecs; + route_head *track_head; + waypoint *wpt_tmp; + + fread(&scount, sizeof(scount), 1, mapsend_file_in); + trk_name = xmalloc(scount + 1); + fread(trk_name, scount, 1, mapsend_file_in); + trk_name[scount] = '\0'; + my_fread4(&trk_count, mapsend_file_in); + + track_head = route_head_alloc(); + track_head->rte_name = trk_name; + track_add_head(track_head); + + while (trk_count--) { + my_fread8(&wpt_long, mapsend_file_in); + my_fread8(&wpt_lat, mapsend_file_in); + if (mapsend_infile_version < 36) { /* < version 4.0 */ + my_fread4(&i, mapsend_file_in); + wpt_alt = i; + } else { + my_fread4(&f, mapsend_file_in); + wpt_alt = f; + } + my_fread4(&time, mapsend_file_in); + my_fread4(&valid, mapsend_file_in); + + /* centiseconds only in >= version 3.0 */ + if (mapsend_infile_version >= 34) { + fread(¢isecs, 1, 1, mapsend_file_in); + } else { + centisecs = 0; + } + + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + wpt_tmp->latitude = -wpt_lat; + wpt_tmp->longitude = wpt_long; + wpt_tmp->creation_time = time; + wpt_tmp->centiseconds = centisecs; + wpt_tmp->altitude = wpt_alt; + route_add_wpt(track_head, wpt_tmp); + } +} + +static void +mapsend_read(void) +{ + mapsend_hdr hdr; + int type; + char buf[3]; + + /* + * Because of the silly struct packing and the goofy variable-length + * strings, each member has to be read in one at a time. Grrr. + */ + + fread(&hdr, sizeof(hdr), 1, mapsend_file_in); + type = le_read16(&hdr.ms_type); + strncpy(buf, hdr.ms_version, 2); + buf[2] = '\0'; + + mapsend_infile_version = atoi(buf); + + switch(type) { + case ms_type_wpt: + mapsend_wpt_read(); + break; + case ms_type_track: + mapsend_track_read(); + break; + case ms_type_log: + fatal(MYNAME ", GPS logs not supported.\n"); + case ms_type_rgn: + fatal(MYNAME ", GPS regions not supported.\n"); + default: + fatal(MYNAME ", unknown file type %d\n", type); + } +} + + +static void +mapsend_waypt_pr(const waypoint *waypointp) +{ + int n; + unsigned char c; + double falt; + double flong; + double flat; + static int cnt = 0; + const char *iconp = NULL; + const char *sn = global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, waypointp->description) : + waypointp->shortname; + + c = sn ? strlen(sn) : 0; + fwrite(&c, 1, 1, mapsend_file_out); + fwrite(sn, c, 1, mapsend_file_out); + + if (waypointp->description) + c = strlen(waypointp->description); + else + c = 0; + + if (c > 30) c = 30; + fwrite(&c, 1, 1, mapsend_file_out); + fwrite(waypointp->description, c, 1, mapsend_file_out); + + /* #, icon, status */ + n = ++cnt; + my_fwrite4(&n, mapsend_file_out); + + if (waypointp->icon_descr) { + iconp = mag_find_token_from_descr(waypointp->icon_descr); + if (1 == strlen(iconp)) { + c = iconp[0] - 'a'; + } else { + c = iconp[1] - 'a' + 26; + } + } else { + c = 0; + } + if (get_cache_icon(waypointp)) { + iconp = mag_find_token_from_descr(get_cache_icon(waypointp)); + if (1 == strlen(iconp)) { + c = iconp[0] - 'a'; + } else { + c = iconp[1] - 'a' + 26; + } + } + + fwrite(&c, 1, 1, mapsend_file_out); + c = 1; + fwrite(&c, 1, 1, mapsend_file_out); + + falt = waypointp->altitude; + if (falt == unknown_alt) + falt = 0; + my_fwrite8(&falt, mapsend_file_out); + + flong = waypointp->longitude; + my_fwrite8(&flong, mapsend_file_out); + flat = -waypointp->latitude; + my_fwrite8(&flat, mapsend_file_out); +} + +static void +mapsend_route_hdr(const route_head *rte) +{ + int i; + unsigned char c; + char * rname; + + /* route name -- mapsend really seems to want something here.. */ + if (!rte->rte_name) + rname = xstrdup("Route"); + else + rname = xstrdup(rte->rte_name); + + c = strlen(rname); + + fwrite(&c, 1, 1, mapsend_file_out); + fwrite(rname, c, 1, mapsend_file_out); + + xfree(rname); + + /* route # */ + i = rte->rte_num; + my_fwrite4(&i, mapsend_file_out); + + i = rte->rte_waypt_ct; + + /* # of waypoints to follow... */ + my_fwrite4(&i, mapsend_file_out); +} + +static void +mapsend_noop(const route_head *wp) +{ + /* no-op */ +} + +static void +mapsend_route_disp(const waypoint *waypointp) +{ + unsigned char c; + const char *iconp; + double dbl; + + route_wp_count++; + + /* waypoint name */ + c = waypointp->shortname ? strlen(waypointp->shortname) : 0; + fwrite(&c, 1, 1, mapsend_file_out); + fwrite(waypointp->shortname, c, 1, mapsend_file_out); + + /* waypoint number */ + my_fwrite4(&route_wp_count, mapsend_file_out); + + dbl = waypointp->longitude; + my_fwrite8(&dbl, mapsend_file_out); + + dbl = -waypointp->latitude; + my_fwrite8(&dbl, mapsend_file_out); + + if (waypointp->icon_descr) { + iconp = mag_find_token_from_descr(waypointp->icon_descr); + if (1 == strlen(iconp)) { + c = iconp[0] - 'a'; + } else { + c = iconp[1] - 'a' + 26; + } + } else { + c = 0; + } + fwrite(&c, 1, 1, mapsend_file_out); +} + +void mapsend_track_hdr(const route_head * trk) +{ + /* + * we write mapsend v3.0 tracks as mapsend v2.0 tracks get + * tremendously out of whack time/date wise. + */ + char *verstring = "30"; + queue *elem, *tmp; + char *tname; + unsigned char c; + int i; + mapsend_hdr hdr = {13, "4D533334 MS", "30", ms_type_track, {0}}; + + switch (trk_version) { + case 20: verstring = "30"; break; + case 30: verstring = "34"; break; + case 40: verstring = "36"; break; + default: fatal("Unknown track version."); break; + } + + hdr.ms_version[0] = verstring[0]; + hdr.ms_version[1] = verstring[1]; + + fwrite(&hdr, sizeof(hdr), 1, mapsend_file_out); + + /* track name */ + if (!trk->rte_name) + tname = xstrdup("Track"); + else + tname = xstrdup(trk->rte_name); + + c = strlen(tname); + + fwrite(&c, 1, 1, mapsend_file_out); + fwrite(tname, c, 1, mapsend_file_out); + xfree(tname); + + /* total nodes (waypoints) this track */ + i = 0; + QUEUE_FOR_EACH(&trk->waypoint_list, elem, tmp) { + i++; + } + + my_fwrite4(&i, mapsend_file_out); + +} + +void mapsend_track_disp(const waypoint * wpt) +{ + unsigned char c; + double dbl; + int i; + int t; + int valid = 1; + static int last_time; + + /* + * Firmware Ver 4.06 (at least) has a defect when it's set for .01km + * tracking that will sometimes result in timestamps in the track + * going BACKWARDS. When mapsend sees this, it (stupidly) advances + * the date by one, ignoring the date on the TRK lines. This looks + * for time travel and just uses the previous time - it's better to + * be thought to be standing still than to be time-travelling! + * + * This is rumoured (but yet unconfirmed) to be fixed in f/w 5.12. + */ + t = wpt->creation_time; + if (t < last_time) { + t = last_time; + } + + /* x = longitude */ + dbl = wpt->longitude; + my_fwrite8(&dbl, mapsend_file_out); + + /* x = latitude */ + dbl = -wpt->latitude; + my_fwrite8(&dbl, mapsend_file_out); + + /* altitude */ + i = wpt->altitude; + my_fwrite4(&i, mapsend_file_out); + + /* time */ + my_fwrite4(&t, mapsend_file_out); + last_time = t; + + /* validity */ + my_fwrite4(&valid, mapsend_file_out); + + /* 0 centiseconds */ + if (trk_version >= 30) { + c = wpt->centiseconds; + fwrite(&c, 1, 1, mapsend_file_out); + } +} + +void +mapsend_track_write(void) +{ + track_disp_all(mapsend_track_hdr, mapsend_noop, mapsend_track_disp); +} + +static void +mapsend_wpt_write(void) +{ + mapsend_hdr hdr = {13, {"4D533330 MS"}, {"30"}, ms_type_wpt, {0}}; + int wpt_count = waypt_count(); + int n = 0; + + if (global_opts.objective == trkdata) { + mapsend_track_write(); + } else { + fwrite(&hdr, sizeof(hdr), 1, mapsend_file_out); + + if (global_opts.objective == wptdata) { + my_fwrite4(&wpt_count, mapsend_file_out); + waypt_disp_all(mapsend_waypt_pr); + } else + if (global_opts.objective == rtedata) { + + /* # of points - all routes */ + n = route_waypt_count(); + my_fwrite4(&n, mapsend_file_out); + + /* write points - all routes */ + route_disp_all(mapsend_noop, mapsend_noop, mapsend_waypt_pr); + } + + n = route_count(); + + my_fwrite4(&n, mapsend_file_out); + + if (n) + route_disp_all(mapsend_route_hdr, mapsend_noop, mapsend_route_disp); + } +} + + + +ff_vecs_t mapsend_vecs = { + ff_type_file, + mapsend_rd_init, + mapsend_wr_init, + mapsend_rd_deinit, + mapsend_wr_deinit, + mapsend_read, + mapsend_wpt_write, + NULL +}; diff --git a/mapsend.h b/mapsend.h new file mode 100644 index 000000000..2d1ef9448 --- /dev/null +++ b/mapsend.h @@ -0,0 +1,44 @@ +/* + Access to MapSend files. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + * + * Information from: + * Mapsend File Format Description Revision 1.1, March 6, 2002 from Thales. + * + * Note this file format was clearly NOT designed for cross-architecture + * portability. In fact, because of the pascal nature of the 'string' + * data type described in that document, it's impractical to describe + * a 'struct waypoint' in C. + * + */ + +typedef struct { + char ms_length; + char ms_signature[11]; + char ms_version[2]; + char ms_type; + char _ms_type[3]; +} mapsend_hdr; + +typedef enum { + ms_type_rgn = 0, + ms_type_wpt = 1, + ms_type_track = 2, + ms_type_log = 3 +} ms_type; diff --git a/mapsource.c b/mapsource.c new file mode 100644 index 000000000..d303814ac --- /dev/null +++ b/mapsource.c @@ -0,0 +1,2174 @@ +/* + Access to Garmin MapSource files. + Based on information provided by Ian Cowley & Mark Bradley + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + */ + +/* #define MPS_DEBUG 0 */ + +#include +#include + +#include "defs.h" +#include "garmin_tables.h" +#include + +static FILE *mps_file_in; +static FILE *mps_file_out; +static FILE *mps_file_temp; +static void *mkshort_handle; + +static int mps_ver_in = 0; +static int mps_ver_out = 0; +static int mps_ver_temp = 0; + +/* Temporary pathname used when merging gpsbabel output with an existing file */ +static char tempname[256]; +static char origname[256]; + +static const waypoint *prevRouteWpt; +/* Private queues of written out waypoints */ +static queue written_wpt_head; +static queue written_route_wpt_head; +static void *written_wpt_mkshort_handle; + +/* Private queue of read in waypoints assumed to be used only for routes */ +static queue read_route_wpt_head; +static void *read_route_wpt_mkshort_handle; + +#define MPSDEFAULTWPTCLASS 0 +#define MPSHIDDENROUTEWPTCLASS 8 + +#define MYNAME "MAPSOURCE" +#define ISME 0 +#define NOTME 1 + +#define DEFAULTICONDESCR "Waypoint" +#define DEFAULTICONVALUE 18 + +#define MPSNAMEBUFFERLEN 1024 +#define MPSNOTESBUFFERLEN 4096 +#define MPSDESCBUFFERLEN 4096 + +char *snlen = NULL; +char *snwhiteopt = NULL; +char *mpsverout = NULL; +char *mpsmergeout = NULL; +char *mpsusedepth = NULL; +char *mpsuseprox = NULL; + +static +arglist_t mps_args[] = { + {"snlen", &snlen, "Length of generated shortnames", NULL, ARGTYPE_INT }, + { "snwhite", &snwhiteopt, "(0/1) Allow whitespace synth. shortnames", + NULL, ARGTYPE_BOOL}, + {"mpsverout", &mpsverout, + "Version of mapsource file to generate (3,4,5)", NULL, + ARGTYPE_INT }, + {"mpsmergeout", &mpsmergeout, "Merge output with existing file", + NULL, ARGTYPE_BOOL }, + {"mpsusedepth", &mpsusedepth, + "Use depth values on output (default is ignore)", NULL, + ARGTYPE_BOOL }, + {"mpsuseprox", &mpsuseprox, + "Use proximity values on output (default is ignore)", + NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + +/* + * A wrapper to ensure the doubles we fwrite are in correct endianness. + */ + +le_fwrite64(void *ptr, int sz, int ct, FILE *stream) +{ + unsigned char cbuf[8]; + + if ((sz != 8) || (ct != 1)) { + fatal(MYNAME ": Bad internal arguments to le_fwrite64"); + } + + le_read64(cbuf, ptr); + fwrite(cbuf, 8, 1, stream); +} + +le_fread64(void *ptr, int sz, int ct, FILE *stream) +{ + unsigned char cbuf[8]; + + fread(cbuf, 8, 1, stream); + le_read64(ptr, cbuf); +} + +static void +mps_noop(const route_head *wp) +{ + /* no-op */ +} + +void +mps_wpt_q_init(queue *whichQueue) +{ + QUEUE_INIT(whichQueue); +} + +void +mps_wpt_q_deinit(queue *whichQueue) +{ + queue *elem, *tmp; + + QUEUE_FOR_EACH(whichQueue, elem, tmp) { + waypoint *q = (waypoint *) dequeue(elem); + waypt_free(q); + } +} + +/* + * Find a waypoint that we've already written out + * + */ +waypoint * +mps_find_wpt_q_by_name(const queue *whichQueue, const char *name) +{ + queue *elem, *tmp; + waypoint *waypointp; + + QUEUE_FOR_EACH(whichQueue, elem, tmp) { + waypointp = (waypoint *) elem; + if (0 == strcmp(waypointp->shortname, name)) { + return waypointp; + } + } + return NULL; +} + +/* + * Add a waypoint that we've already written out to our list + * + */ +void +mps_wpt_q_add(const queue *whichQueue, const waypoint *wpt) +{ + waypoint *written_wpt = waypt_dupe(wpt); + ENQUEUE_TAIL(whichQueue, &written_wpt->Q); +} + +const char * +mps_find_desc_from_icon_number(const int icon, garmin_formats_e garmin_format) +{ + icon_mapping_t *i; + + for (i = garmin_icon_table; i->icon; i++) { + switch (garmin_format) { + case MAPSOURCE: + if (icon == i->mpssymnum) + return i->icon; + break; + case PCX: + case GARMIN_SERIAL: + if (icon == i->pcxsymnum) + return i->icon; + break; + default: + fatal(MYNAME ": unknown garmin format"); + } + } + return DEFAULTICONDESCR; +} + +int +mps_find_icon_number_from_desc(const char *desc, garmin_formats_e garmin_format) +{ + icon_mapping_t *i; + int def_icon = DEFAULTICONVALUE; + int n; + + if (!desc) + return def_icon; + + /* + * If we were given a numeric icon number as a description + * (i.e. 8255), just return that. + */ + n = atoi(desc); + if (n) { + return n; + } + + for (i = garmin_icon_table; i->icon; i++) { + if (case_ignore_strcmp(desc,i->icon) == 0) { + switch (garmin_format) { + case MAPSOURCE: + return i->mpssymnum; + case PCX: + case GARMIN_SERIAL: + return i->pcxsymnum; + default: + fatal(MYNAME ": unknown garmin format"); + } + } + } + return def_icon; +} + +int mps_converted_icon_number(const int icon_num, const int mpsver, garmin_formats_e garmin_format) +{ + int def_icon = DEFAULTICONVALUE; + + switch (garmin_format) { + case MAPSOURCE: + if (mpsver == 5) return icon_num; + if (mpsver == 4) { + /* Water hydrant */ + if (icon_num == 139) return def_icon; + else return icon_num; + } + else { + /* the Contact icons - V3 doesn't have anything like this */ + if ((icon_num >= 119) && (icon_num <= 138)) return def_icon; + /* the Geocache icons - V3 use the Circle with X */ + if ((icon_num >= 117) && (icon_num <= 118)) return 65; + /* Water hydrant */ + if (icon_num == 139) return def_icon; + return icon_num; + } + + case PCX: + case GARMIN_SERIAL: + if (mpsver == 5) return icon_num; + if (mpsver == 4) { + /* Water hydrant */ + if (icon_num == 8282) return def_icon; + else return icon_num; + } + /* the Contact icons - V3 doesn't have anything like this */ + if ((icon_num >= 8257) && (icon_num <= 8276)) return def_icon; + /* the Geocache icons - V3 use the Circle with X */ + if ((icon_num >= 8255) && (icon_num <= 8256)) return 179; + /* Water hydrant */ + if (icon_num == 8282) return def_icon; + return icon_num; + + default: + fatal(MYNAME ": unknown garmin format"); + } + return def_icon; +} + +static void +mps_rd_init(const char *fname) +{ + mps_file_in = xfopen(fname, "rb", MYNAME); + + read_route_wpt_mkshort_handle = mkshort_new_handle(); + /* initialise the "private" queue of waypoints read for routes */ + mps_wpt_q_init(&read_route_wpt_head); +} + +static void +mps_rd_deinit(void) +{ + fclose(mps_file_in); + if ( read_route_wpt_mkshort_handle ) { + mkshort_del_handle( read_route_wpt_mkshort_handle ); + } + /* flush the "private" queue of waypoints read for routes */ + mps_wpt_q_deinit(&read_route_wpt_head); +} + +static void +mps_wr_init(const char *fname) +{ + if (mpsmergeout) { + mps_file_out = xfopen(fname, "rb", MYNAME); + if (mps_file_out == NULL) { + mpsmergeout = NULL; + } + else { + fclose(mps_file_out); + srand((unsigned) current_time()); + + for (;;) { + /* create a temporary name based on a random char and the existing name */ + /* then test if it already exists, if so try again with another rand num */ + /* yeah, yeah, so there's probably a library function for this */ + sprintf(tempname, "%s.%08x", fname, rand()); + mps_file_temp = fopen(tempname, "rb"); + if (mps_file_temp == NULL) break; + fclose(mps_file_temp); + } + rename(fname, tempname); + mps_file_temp = xfopen(tempname, "rb", MYNAME); + strcpy(origname, fname); /* save in case we need to revert the renamed file */ + } + } + + mps_file_out = xfopen(fname, "wb", MYNAME); + + written_wpt_mkshort_handle = mkshort_new_handle(); + /* initialise the "private" queue of waypoints written */ + mps_wpt_q_init(&written_wpt_head); + mps_wpt_q_init(&written_route_wpt_head); +} + +static void +mps_wr_deinit(void) +{ + fclose(mps_file_out); + + if (mpsmergeout) { + fclose(mps_file_temp); + remove(tempname); + } + + if ( written_wpt_mkshort_handle ) { + mkshort_del_handle( written_wpt_mkshort_handle ); + } + /* flush the "private" queue of waypoints written */ + mps_wpt_q_deinit(&written_wpt_head); + mps_wpt_q_deinit(&written_route_wpt_head); +} + +/* + * get characters until and including terminating NULL from mps_file_in + * and write into buf. + */ +static void +mps_readstr(FILE *mps_file, char *buf, size_t sz) +{ + int c; + while (sz-- && (c = fgetc (mps_file)) != EOF) { + *buf++ = c; + if (c == 0) { + return; + } + } +} + +/* + * read in from file to check a) valid format b) version of data formating + * MRCB + */ +static void +mps_fileHeader_r(FILE *mps_file, int *mps_ver) +{ + char hdr[100]; + int reclen; + + mps_readstr(mps_file, hdr, sizeof(hdr)); + if ( strcmp( hdr, "MsRcd" )) { + fatal(MYNAME ": This doesn't look like a mapsource file.\n"); + } + /* Read record length of "format details" section */ + fread(&reclen, 4, 1, mps_file); + reclen = le_read32(&reclen); + /* Read the "format details" in plus the trailing null */ + fread( hdr, 3, 1, mps_file); + if (hdr[0] != 'D') { + /* No flag for the "data" section */ + fatal(MYNAME ": This doesn't look like a mapsource file.\n"); + } + if (hdr[1] == 'd') { + *mps_ver = 3; + } + else if ((hdr[1] > 'd') && (hdr[1] <= 'h')) { + *mps_ver = 4; + } + else if ((hdr[1] > 'h') && (hdr[1] <= 'i')) { + *mps_ver = 5; + } + else { + fatal(MYNAME ": Unsuppported version of mapsource file.\n"); + } + /* Skip reliably over the "format details" section */ + fseek( mps_file, reclen+1-3, SEEK_CUR); + /* Read record length of "program signature" section */ + fread(&reclen, 4, 1, mps_file); + reclen = le_read32(&reclen); + /* Skip reliably over the "program signature" section */ + if (reclen >= 0) fseek(mps_file, reclen+1, SEEK_CUR); +} + +/* + * write out to file + * MRCB + */ +static void +mps_fileHeader_w(FILE *mps_file, int mps_ver) +{ + char hdr[100]; + int reclen; + + strcpy (hdr, "MsRc"); + fwrite(hdr, 4, 1, mps_file); + + /* Between versions 3 & 5 this value is 'd', but might change in the future */ + strcpy(hdr, "d"); + fwrite(hdr, 2, 1, mps_file); /* include trailing NULL char */ + + /* Start of a "Data" section */ + hdr[0] = 'D'; + /* if (mps_ver == 3) */ + hdr[1] = 'd'; /* equates to V3.02 */ + if (mps_ver == 4) hdr[1] = 'g'; /* equates to V4.06 */ + if (mps_ver == 5) hdr[1] = 'i'; /* equates to V5.0 */ + hdr[2] = 0; + + reclen = 2; /* this is 3 byte record */ + le_write32(&reclen, reclen); + fwrite(&reclen, 4, 1, mps_file); + fwrite(hdr, 3, 1, mps_file); /* reclen + 1 */ + + hdr[0] = 'A'; + /* if (mps_ver == 3) */ + hdr[1] = 0x2E; hdr[2] = 0x01; /* equates to V3.02 */ + hdr[3] = 'S'; + hdr[4] = 'Q'; + hdr[5] = 'A'; + hdr[6] = 0; + strcpy(hdr+7,"Oct 20 1999"); + strcpy(hdr+19,"12:50:33"); + if (mps_ver == 4) { + hdr[1] = 0x96; /* equates to V4.06 */ + strcpy(hdr+7,"Oct 22 2001"); + strcpy(hdr+19,"15:45:33"); + } + if (mps_ver == 5) { + hdr[1] = 0xF4; /* equates to V5.0 */ + strcpy(hdr+7,"Jul 3 2003"); + strcpy(hdr+19,"08:35:33"); + } + + reclen = 27; /* pre measured! */ + le_write32(&reclen, reclen); + fwrite(&reclen, 4, 1, mps_file); + fwrite(hdr, 28, 1, mps_file); /* reclen + 1 - can't use this as reclen may be wrongendian now */ +} + +/* + * read in from file a map segment record + * MRCB + */ +static void +mps_mapsegment_r(FILE *mps_file, int mps_ver) +{ + char hdr[100]; + int reclen; + + /* At the moment we're not doing anything with map segments, but here's the template code as if we were + fread(&CDid, 4, 1, mps_file); + reclen = le_read32(&CDid); + + fread(&CDSegmentid, 4, 1, mps_file); + reclen = le_read32(&CDSegmentid); + + mps_readstr(mps_file, CDName, sizeof(CDName)); + mps_readstr(mps_file, CDSegmentName, sizeof(CDSegmentName)); + mps_readstr(mps_file, CDAreaName, sizeof(CDAreaName)); + + fread(hdr, 4, 1, mps_file); /* trailing long value */ + + fseek(mps_file, -5, SEEK_CUR); + fread(&reclen, 4, 1, mps_file); + reclen = le_read32(&reclen); + if (reclen >= 0) fseek( mps_file, reclen+1, SEEK_CUR); + return; +} + + +/* + * read in from file a mapsetname record + * there should always be one of these at the end of the file + * MRCB + */ +static void +mps_mapsetname_r(FILE *mps_file, int mps_ver) +{ + char hdr[100]; + int reclen; + + /* At the moment we're not doing anything with mapsetnames, but here's the template code as if we were + mps_readstr(mps_file, hdr, sizeof(hdr)); + char mapsetnamename[very large number?]; + strcpy(mapsetnamename,hdr); + char mapsetnameAutonameFlag; + fread(&mapsetnameAutonameFlag, 1, 1, mps_file); */ + + fseek(mps_file, -5, SEEK_CUR); + fread(&reclen, 4, 1, mps_file); + reclen = le_read32(&reclen); + fseek( mps_file, reclen+1, SEEK_CUR); + return; +} + + +/* + * write out to file a mapsetname record + * there should always be one of these at the end of the file + * MRCB + */ +static void +mps_mapsetname_w(FILE *mps_file, int mps_ver) +{ + char hdr[100]; + int reclen; + + hdr[0] = 'V'; /* mapsetname start of record indicator */ + hdr[1] = 0; /* zero length null terminated string */ + hdr[2] = 1; /* mapsetname autoname flag set to DO autoname */ + reclen = 2; /* three bytes of the V record */ + le_write32(&reclen, reclen); + fwrite(&reclen, 4, 1, mps_file); + fwrite(hdr, 3, 1, mps_file); /* reclen + 1 */ +} + + +/* + * read in from file a waypoint record + * MRCB + */ +static void +mps_waypoint_r(FILE *mps_file, int mps_ver, waypoint **wpt, unsigned int *mpsclass) +{ + char tbuf[100]; + char wptname[MPSNAMEBUFFERLEN]; + char wptdesc[MPSDESCBUFFERLEN]; + char wptnotes[MPSNOTESBUFFERLEN]; + int lat; + int lon; + int icon; + + waypoint *thisWaypoint = NULL; + double mps_altitude = unknown_alt; + double mps_proximity = unknown_alt; + double mps_depth = unknown_alt; + + thisWaypoint = waypt_new(); + *wpt = thisWaypoint; + + mps_readstr(mps_file, wptname, sizeof(wptname)); + + fread(mpsclass, 4, 1, mps_file); /* class */ + (*mpsclass) = le_read32(mpsclass); + mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */ + + fread(tbuf,17, 1, mps_file); /* subclass data (17) */ + + if ((mps_ver == 4) || (mps_ver == 5)) { + fread(tbuf, 5, 1, mps_file); /* additional subclass data (1) & terminator? (4) */ + } + + fread(&lat, 4, 1, mps_file); + fread(&lon, 4, 1, mps_file); + lat = le_read32(&lat); + lon = le_read32(&lon); + + fread(tbuf, 1, 1, mps_file); /* altitude validity */ + if (tbuf[0] == 1) { + le_fread64(&mps_altitude,sizeof(mps_altitude),1,mps_file); + } + else { + mps_altitude = unknown_alt; + le_fread64(tbuf,sizeof(mps_altitude),1, mps_file); + } + + mps_readstr(mps_file, wptdesc, sizeof(wptdesc)); + + fread(tbuf, 1, 1, mps_file); /* proximity validity */ + if (tbuf[0] == 1) { + le_fread64(&mps_proximity,sizeof(mps_proximity),1,mps_file); + } + else { + mps_proximity = unknown_alt; + le_fread64(tbuf,sizeof(mps_proximity),1, mps_file); + } + + fread(tbuf, 4, 1, mps_file); /* display flag */ + fread(tbuf, 4, 1, mps_file); /* colour */ + fread(&icon, 4, 1, mps_file); /* display symbol */ + icon = le_read32(&icon); + + mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* city */ + mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* state */ + mps_readstr(mps_file, tbuf, sizeof(tbuf)); /*facility */ + + fread(tbuf, 1, 1, mps_file); /* unknown */ + + fread(tbuf, 1, 1, mps_file); /* depth validity */ + if (tbuf[0] == 1) { + le_fread64(&mps_depth,sizeof(mps_depth),1,mps_file); + } + else { + mps_depth = unknown_alt; + le_fread64(tbuf,sizeof(mps_depth),1, mps_file); + } + + if ((mps_ver == 4) || (mps_ver == 5)) { + fread(tbuf, 6, 1, mps_file); /* unknown */ + mps_readstr(mps_file, wptnotes, sizeof(wptnotes)); + } + else { + fread(tbuf, 2, 1, mps_file); /* unknown */ + } + + thisWaypoint->shortname = xstrdup(wptname); + thisWaypoint->description = xstrdup(wptdesc); + thisWaypoint->notes = xstrdup(wptnotes); + thisWaypoint->latitude = lat / 2147483648.0 * 180.0; + thisWaypoint->longitude = lon / 2147483648.0 * 180.0; + thisWaypoint->altitude = mps_altitude; + thisWaypoint->proximity = mps_proximity; + thisWaypoint->depth = mps_depth; + + /* might need to change this to handle version dependent icon handling */ + thisWaypoint->icon_descr = mps_find_desc_from_icon_number(icon, MAPSOURCE); + + /* The following Now done elsewhere since it can be useful to read in and + perhaps not add to the list */ + /* waypt_add(thisWaypoint); */ + + return; +} + +/* + * write out to file a waypoint record + * MRCB + */ +static void +mps_waypoint_w(FILE *mps_file, int mps_ver, const waypoint *wpt, const int isRouteWpt) +{ + unsigned char hdr[100]; + int reclen; + int lat = wpt->latitude / 180.0 * 2147483648.0; + int lon = wpt->longitude / 180.0 * 2147483648.0; + int icon; + char *src; + char *ident; + char *ascii_description; + char zbuf[25]; + char ffbuf[25]; + int display = 1; + int colour = 0; /* (unknown colour) black is 1, white is 16 */ + + double mps_altitude = wpt->altitude; + double mps_proximity = (mpsuseprox ? wpt->proximity : unknown_alt); + double mps_depth = (mpsusedepth ? wpt->depth : unknown_alt); + + if(wpt->description) src = wpt->description; + if(wpt->notes) src = wpt->notes; + ident = global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, src) : + wpt->shortname; + + memset(zbuf, 0, sizeof(zbuf)); + memset(ffbuf, 0xff, sizeof(ffbuf)); + + /* might need to change this to handle version dependent icon handling */ + icon = mps_find_icon_number_from_desc(wpt->icon_descr, MAPSOURCE); + + if (get_cache_icon(wpt) /* && wpt->icon_descr && (strcmp(wpt->icon_descr, "Geocache Found") != 0)*/) { + icon = mps_find_icon_number_from_desc(get_cache_icon(wpt), MAPSOURCE); + } + + icon = mps_converted_icon_number(icon, mps_ver, MAPSOURCE); + + /* two NULL (0x0) bytes at end of each string */ + ascii_description = wpt->description ? str_utf8_to_ascii(wpt->description) : xstrdup(""); + reclen = strlen(ident) + strlen(ascii_description) + 2; + if ((mps_ver == 4) || (mps_ver == 5)) { + /* v4.06 & V5.0*/ + reclen += 85; /* "W" (1) + strlen(name) + NULL (1) + class(4) + country(sz) + + subclass(18) + unknown(4) + lat(4) + lon(4) + alt(9) + strlen(desc) + + NULL (1) + prox(9) + display(4) + colour(4) + symbol(4) + city(sz) + + state(sz) + facility(sz) + unknown2(1) + depth(9) + unknown3(7) */ + /* -1 as reclen is interpreted from zero meaning a reclength of one */ + if (wpt->notes) reclen += strlen(wpt->notes); + } + else { + /* v3.02 */ + reclen += 75; /* "W" (1) + strlen(name) + NULL (1) + + class(4) + country(sz) + + subclass(17) + lat(4) + lon(4) + alt(9) + strlen(desc) + + NULL (1) + prox(9) + display(4) + + colour(4) + symbol(4) + city(sz) + state(sz) + facility(sz) + + unknown2(1) + depth(9) + unknown3(2) */ + /* -1 as reclen is interpreted from zero meaning a reclength of one */ + } + + le_write32(&reclen, reclen); + fwrite(&reclen, 4, 1, mps_file); + fwrite("W", 1, 1, mps_file); + fputs(ident, mps_file); + fwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */ + + if (isRouteWpt) zbuf[0] = (char)MPSHIDDENROUTEWPTCLASS; + else zbuf[0] = (char)MPSDEFAULTWPTCLASS; + fwrite(zbuf, 4, 1, mps_file); /* class */ + + zbuf[0]=0; + fwrite(zbuf, 1, 1, mps_file); /* country empty string */ + + if ((mps_ver == 4) || (mps_ver == 5)) { + fwrite(zbuf, 4, 1, mps_file); /* subclass part 1 */ + fwrite(ffbuf, 12, 1, mps_file); /* subclass part 2 */ + fwrite(zbuf, 2, 1, mps_file); /* subclass part 3 */ + fwrite(ffbuf, 4, 1, mps_file); /* unknown */ + } + else { + fwrite(zbuf, 8, 1, mps_file); + fwrite(ffbuf, 8, 1, mps_file); + fwrite(zbuf, 1, 1, mps_file); + } + + le_write32(&lat, lat); + le_write32(&lon, lon); + fwrite(&lat, 4, 1, mps_file); + fwrite(&lon, 4, 1, mps_file); + + if (mps_altitude == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&mps_altitude, 8 , 1, mps_file); + } + if (wpt->description) fputs(ascii_description, mps_file); + fwrite(zbuf, 1, 1, mps_file); /* NULL termination */ + xfree(ascii_description); + ascii_description = NULL; + + if (mps_proximity == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&mps_proximity, 8 , 1, mps_file); + } + + le_write32(&display, display); + fwrite(&display, 4, 1, mps_file); /* Show waypoint w/ name */ + + le_write32(&colour, colour); + fwrite(&colour, 4, 1, mps_file); + + le_write32(&icon, icon); + fwrite(&icon, 4, 1, mps_file); + + fwrite(zbuf, 3, 1, mps_file); /* city, state, facility */ + + fwrite(zbuf, 1, 1, mps_file); /* unknown */ + + if (mps_depth == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&mps_depth, 8 , 1, mps_file); + } + + fwrite(zbuf, 2, 1, mps_file); /* unknown */ + if ((mps_ver == 4) || (mps_ver == 5)) { + fwrite(zbuf, 4, 1, mps_file); /* unknown */ + if (wpt->notes) fputs(wpt->notes, mps_file); + fwrite(zbuf, 1, 1, mps_file); /* string termination */ + } +} + +/* + * wrapper to include the mps_ver_out information + * A waypoint is only written if it hasn't been written before + * based on it shortname alone + * + */ +static void +mps_waypoint_w_unique_wrapper(const waypoint *wpt) +{ + waypoint *wptfound = NULL; + + /* Search for this waypoint in the ones already written */ + wptfound = mps_find_wpt_q_by_name(&written_wpt_head, wpt->shortname); + /* is the next line necessary? Assumes we know who's called us and in what order */ + if (wptfound == NULL) + wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, wpt->shortname); + + /* if this waypoint hasn't been written then it is okay to do so */ + if (wptfound == NULL) { + mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==0)); + + /* ensure we record in our "private" queue what has been + written so that we don't write it again */ + mps_wpt_q_add(&written_wpt_head, wpt); + } +} + +/* + * wrapper to include the mps_ver_out information + * A waypoint is only written if it hasn't been written before + * based on it shortname alone + * Provided as a separate function from above in case we find + * have to do other things + * + */ +static void +mps_route_wpt_w_unique_wrapper(const waypoint *wpt) +{ + waypoint *wptfound = NULL; + + /* Search for this waypoint in the ones already written */ + wptfound = mps_find_wpt_q_by_name(&written_wpt_head, wpt->shortname); + if (wptfound == NULL) + /* so, not a real wpt, so must check route wpts already written as reals */ + wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, wpt->shortname); + + /* if this waypoint hasn't been written then it is okay to do so + but assume it is only required for the route + */ + if (wptfound == NULL) { + /* Although we haven't written one out, this might still be a "real" waypoint + If so, we need to write it out now accordingly */ + wptfound = find_waypt_by_name (wpt->shortname); + + if (wptfound == NULL) { + /* well, we tried to find: it wasn't written and isn't a real waypoint */ + mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==1)); + mps_wpt_q_add(&written_route_wpt_head, wpt); + } + else { + mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==0)); + /* Simulated real user waypoint */ + mps_wpt_q_add(&written_wpt_head, wpt); + } + } +} + +/* + * wrapper to include the mps_ver_out information + * This one always writes a waypoint. If it has been written before + * then generate a unique name before writing + * + */ +static void +mps_waypoint_w_uniqloc_wrapper(waypoint *wpt) +{ + waypoint *wptfound = NULL; + char *newName; + unsigned int uniqueNum = 0; + + /* Search for this waypoint in the ones already written */ + wptfound = mps_find_wpt_q_by_name(&written_wpt_head, wpt->shortname); + /* is the next line necessary? Assumes we know who's called us and in what order */ + if (wptfound == NULL) + wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, wpt->shortname); + + if (wptfound != NULL) { + /* check if this is the same waypoint by looking at the lat lon + not ideal, but better then having two same named waypoints + that kills MapSource. If it is the same then don't bother + adding it in. If it isn't, then rename it + */ + if (((wpt->latitude - wptfound->latitude) != 0) || + ((wpt->longitude - wptfound->longitude) != 0)) { + /* Not the same lat lon, so rename and add */ + newName = mkshort(written_wpt_mkshort_handle, wpt->shortname); + wptfound = waypt_dupe(wpt); + xfree(wptfound->shortname); + wptfound->shortname = newName; + mps_waypoint_w(mps_file_out, mps_ver_out, wptfound, (1==0)); + mps_wpt_q_add(&written_wpt_head, wpt); + } + } + else { + mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==0)); + /* ensure we record in out "private" queue what has been + written so that we don't write it again */ + mps_wpt_q_add(&written_wpt_head, wpt); + } +} + +/* + * read in from file a route record + * MRCB + */ +static void +mps_route_r(FILE *mps_file, int mps_ver, route_head **rte) +{ + char tbuf[100]; + char rtename[MPSNAMEBUFFERLEN]; + char wptname[MPSNAMEBUFFERLEN]; + int lat; + int lon; + short int rte_autoname = 0; + int interlinkStepCount; + int thisInterlinkStep; + unsigned int mpsclass; + int FFsRead; + + time_t dateTime = 0; + route_head *rte_head; + int rte_count; + + waypoint *thisWaypoint; + waypoint *tempWpt; + + double mps_altitude = unknown_alt; + double mps_depth = unknown_alt; + + mps_readstr(mps_file, rtename, sizeof(rtename)); +#ifdef MPS_DEBUG + fprintf(stderr, "mps_route_r: reading route %s\n", rtename); +#endif + + fread(&rte_autoname, 2, 1, mps_file); /* autoname flag */ + rte_autoname = le_read16(&rte_autoname); + + fread(&lat, 4, 1, mps_file); + fread(&lon, 4, 1, mps_file); + lat = le_read32(&lat); /* max lat of whole route */ + lon = le_read32(&lon); /* max lon of whole route */ + + fread(tbuf, 1, 1, mps_file); /* altitude validity */ + if (tbuf[0] == 1) { + le_fread64(&mps_altitude,sizeof(mps_altitude),1,mps_file); /* max alt of the whole route */ + } + else { + mps_altitude = unknown_alt; + le_fread64(tbuf,sizeof(mps_altitude),1, mps_file); + } + + fread(&lat, 4, 1, mps_file); + fread(&lon, 4, 1, mps_file); + lat = le_read32(&lat); /* min lat of whole route */ + lon = le_read32(&lon); /* min lon of whole route */ + + fread(tbuf, 1, 1, mps_file); /* altitude validity */ + if (tbuf[0] == 1) { + le_fread64(&mps_altitude,sizeof(mps_altitude),1,mps_file); /* min alt of the whole route */ + } + else { + mps_altitude = unknown_alt; + le_fread64(tbuf,sizeof(mps_altitude),1, mps_file); + } + + fread(&rte_count, 4, 1, mps_file); /* number of waypoints in route */ + rte_count = le_read32(&rte_count); + + /* This might be rather presumptuous, but is it valid in any format to have route with no points? */ + /* Let's assume not, so if the route count is zero or less, let's get out of here and allow the */ + /* caller to do any file resync */ + if (rte_count < 0) return; + +#ifdef MPS_DEBUG + fprintf(stderr, "mps_route_r: route contains %d waypoints\n", rte_count); +#endif + + rte_head = route_head_alloc(); + rte_head->rte_name = xstrdup(rtename); + route_add_head(rte_head); + *rte = rte_head; + + rte_count--; /* need to loop round for one less than the number of waypoints */ + + while (rte_count--) { + + mps_readstr(mps_file, wptname, sizeof(wptname)); +#ifdef MPS_DEBUG + fprintf(stderr, "mps_route_r: reading route waypoint %s\n", wptname); +#endif + + fread(&mpsclass, 4, 1, mps_file); /* class */ + mpsclass = le_read32(&mpsclass); + mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */ + + if ((mps_ver == 4) || (mps_ver == 5)) { + fread(tbuf, 22, 1, mps_file); /* subclass data */ + + /* This is a bit unpleasant. Routes have a variable length of + data (min 22 bytes) terminated by a zero */ + do { + fread(tbuf, 1, 1, mps_file); + } while (tbuf[0]); + + /* The next thing is the unknown 0x03 0x00 .. 0x00 (18 bytes) */ + fread(tbuf, 18, 1, mps_file); + } + else { + fread(tbuf, 17, 1, mps_file); /* subclass data */ + fread(tbuf, 18, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */ + } + + /* link details */ + fread(&interlinkStepCount, 4, 1, mps_file); /* NOT always 2, but will assume > 0 */ + interlinkStepCount = le_read32(&interlinkStepCount); + +#ifdef MPS_DEBUG + fprintf(stderr, "mps_route_r: interlink steps are %d\n", interlinkStepCount); +#endif + + /* Basically we're knackered if the step count is less than one since we hard code reading of the */ + /* first, so if there isn't one, we'd lose sync on the file and read junk */ + /* Given we've already done some route head allocation, do we return or do we die? It'd be good */ + /* do some clean up before returning. */ + if (interlinkStepCount < 1) { + /* For RJL - are the following lines correct ? */ + /* route_free(rte_head); + route_del_head(rte_head); */ + return; + } + + /* first end of link */ + fread(&lat, 4, 1, mps_file); + fread(&lon, 4, 1, mps_file); + lat = le_read32(&lat); + lon = le_read32(&lon); + + fread(tbuf, 1, 1, mps_file); /* altitude validity */ + if (tbuf[0] == 1) { + le_fread64(&mps_altitude,sizeof(mps_altitude),1,mps_file); + } + else { + mps_altitude = unknown_alt; + le_fread64(tbuf,sizeof(mps_altitude),1, mps_file); + } + + /* with MapSource routes, the real waypoint details are held as a separate waypoint, so copy from there + if found. With MapSource, one should consider the real waypoint list as definitive */ + tempWpt = find_waypt_by_name(wptname); + + if (tempWpt != NULL) { + thisWaypoint = waypt_dupe(tempWpt); + } + else { + tempWpt = mps_find_wpt_q_by_name(&read_route_wpt_head, wptname); + + if (tempWpt != NULL) { + thisWaypoint = waypt_dupe(tempWpt); + } + else { + /* should never reach here, but we do need a fallback position */ +#ifdef MPS_DEBUG + fprintf(stderr, "mps_route_r: reached the point we never should\n"); +#endif + thisWaypoint = waypt_new(); + thisWaypoint->shortname = xstrdup(wptname); + thisWaypoint->latitude = lat / 2147483648.0 * 180.0; + thisWaypoint->longitude = lon / 2147483648.0 * 180.0; + thisWaypoint->altitude = mps_altitude; + thisWaypoint->depth = mps_depth; + } + } + + route_add_wpt(rte_head, thisWaypoint); + + /* take two off the count since we separately read the start and end parts of the link */ + /* MRCB 2004/09/15 - NOPE, sorry, this needs to one, since interlink steps can be > 0 */ + for (thisInterlinkStep = interlinkStepCount - 1; thisInterlinkStep > 0; thisInterlinkStep--) { + /* Could do this by doing a calculation on length of each co-ordinate and just doing one read + but doing it this way makes it easier in the future to make use of this data */ + fread(&lat, 4, 1, mps_file); + fread(&lon, 4, 1, mps_file); + lat = le_read32(&lat); + lon = le_read32(&lon); + + fread(tbuf, 1, 1, mps_file); /* altitude validity */ + if (tbuf[0] == 1) { + le_fread64(&mps_altitude,sizeof(mps_altitude),1,mps_file); + } + else { + mps_altitude = unknown_alt; + le_fread64(tbuf,sizeof(mps_altitude),1, mps_file); + } + } + + fread(tbuf, 1, 1, mps_file); /* NULL */ + + fread(tbuf, 4, 1, mps_file); /* link max lat */ + fread(tbuf, 4, 1, mps_file); /* link max lon */ + fread(tbuf, 9, 1, mps_file); /* link max alt validity + alt */ + + fread(tbuf, 4, 1, mps_file); /* link min lat */ + fread(tbuf, 4, 1, mps_file); /* link min lon */ + fread(tbuf, 9, 1, mps_file); /* link min alt validity + alt */ + + } /* while (trk_count--) */ + + /* when the loop is done, there's still one waypoint to read with a small trailer */ + /* all we want is the waypoint name; lat, lon and alt are already set from above */ + mps_readstr(mps_file, wptname, sizeof(wptname)); +#ifdef MPS_DEBUG + fprintf(stderr, "mps_route_r: reading final route waypoint %s\n", wptname); +#endif + + + fread(&mpsclass, 4, 1, mps_file); /* class */ + mpsclass = le_read32(&mpsclass); + mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */ + + if ((mps_ver == 4) || (mps_ver == 5)) { + fread(tbuf, 22, 1, mps_file); /* subclass data */ + + /* This is a bit unpleasant. Routes have a variable length of + data (min 22 bytes) terminated by a zero */ + do { + fread(tbuf, 1, 1, mps_file); + } while (tbuf[0]); + + /* The next thing is the unknown 0x03 0x00 .. 0x00 (18 bytes) */ + fread(tbuf, 18, 1, mps_file); + } + else { + fread(tbuf, 17, 1, mps_file); /* subclass data */ + fread(tbuf, 18, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */ + } + + fread(tbuf, 5, 1, mps_file); /* 5 byte trailer */ + /* with MapSource routes, the real waypoint details are held as a separate waypoint, so copy from there + if found because there is more info held in a real waypoint than in its route counterpart, + e.g. the display symbol (aka icon) + */ + tempWpt = find_waypt_by_name(wptname); + + if (tempWpt != NULL) { + thisWaypoint = waypt_dupe(tempWpt); + } + else { + tempWpt = mps_find_wpt_q_by_name(&read_route_wpt_head, wptname); + + if (tempWpt != NULL) { + thisWaypoint = waypt_dupe(tempWpt); + } + else { + /* should never reach here, but we do need a fallback position */ + thisWaypoint = waypt_new(); + thisWaypoint->shortname = xstrdup(wptname); + thisWaypoint->latitude = lat / 2147483648.0 * 180.0; + thisWaypoint->longitude = lon / 2147483648.0 * 180.0; + thisWaypoint->altitude = mps_altitude; + } + } + + route_add_wpt(rte_head, thisWaypoint); + + return; +} + +/* + * write out to file a route header + * MRCB + */ +static void +mps_routehdr_w(FILE *mps_file, int mps_ver, const route_head *rte) +{ + unsigned int reclen; + unsigned int rte_datapoints; + unsigned int colour = 0; /* unknown colour */ + int rname_len; + char *rname; + char hdr[20]; + char zbuf[20]; + char *src; + char *ident; + + waypoint *testwpt; + time_t uniqueValue; + int allWptNameLengths; + + double maxlat=-90.0; + double maxlon=-180.0; + double minlat=90.0; + double minlon=180.0; + double maxalt=unknown_alt; + double minalt=unknown_alt; + + int lat; + int lon; + + queue *elem, *tmp; + + prevRouteWpt = NULL; /* clear the stateful flag used to know when the start of route wpts happens */ + + memset(zbuf, 0, sizeof(zbuf)); + + /* total nodes (waypoints) this route */ + rte_datapoints = 0; + allWptNameLengths = 0; + + if (rte->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid route - treat as a placeholder for now */ + QUEUE_FOR_EACH(&rte->waypoint_list, elem, tmp) { + testwpt = (waypoint *)elem; + if (rte_datapoints == 0) { + uniqueValue = testwpt->creation_time; + } + if (testwpt->latitude > maxlat) maxlat = testwpt->latitude; + if (testwpt->latitude < minlat) minlat = testwpt->latitude; + if (testwpt->longitude > maxlon) maxlon = testwpt->longitude; + if (testwpt->longitude < minlon) minlon = testwpt->longitude; + if (testwpt->altitude != unknown_alt) { + if ((testwpt->altitude > maxalt) || + (maxalt == unknown_alt)) maxalt = testwpt->altitude; + if ((testwpt->altitude < minalt) || + (minalt == unknown_alt)) minalt = testwpt->altitude; + } + + if(testwpt->description) src = testwpt->description; + if(testwpt->notes) src = testwpt->notes; + ident = global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, src) : + testwpt->shortname; + allWptNameLengths += strlen(ident) + 1; + + rte_datapoints++; + } + + if (uniqueValue == 0) { + uniqueValue = current_time(); + } + + /* route name */ + if (!rte->rte_name) { + sprintf(hdr, "Route%04x", uniqueValue); + rname = xstrdup(hdr); + } + else + rname = xstrdup(rte->rte_name); + + rname_len = strlen(rname); + reclen = rname_len + 42; /* "T" (1) + strlen(tname) + NULL (1) + autoname flag (2) + + route lat lon max (2x4) + route max alt (9) + + route lat lon min (2x4) + route min alt (9) + + num route datapoints value (4) */ + + /* V3 - each waypoint: waypoint name + NULL (1) + class (4) + country + NULL (1) + + subclass (17) + unknown (18) */ + /* V4,5 - each waypoint: waypoint name + NULL (1) + class (4) + country + NULL (1) + + subclass (18) + unknown (4) + unknown (19) */ + /* V* - each route link: 0x00000002 (4) + end 1 lat (4) + end 1 lon (4) + end 1 alt (9) + + end 2 lat (4) + end 2 lon (4) + end 2 alt (9) + NULL (1) + + link max lat (4) + link max lon (4) + link max alt (9) + + link min lat (4) + link min lon (4) + link min alt (9) */ + + if ((mps_ver == 4) || (mps_ver == 5)) { + reclen += allWptNameLengths + rte_datapoints * 46 + + (rte_datapoints - 1) * 73 + 4; /* link details plus overall trailing bytes */ + } + else { + reclen += allWptNameLengths + rte_datapoints * 40 + + (rte_datapoints - 1) * 73 + 4; /* link details plus overall trailing bytes */ + } + + le_write32(&reclen, reclen); + fwrite(&reclen, 4, 1, mps_file); + + hdr[0] = 'R'; + fwrite(hdr, 1, 1, mps_file); + + fwrite(rname, rname_len, 1, mps_file); + xfree(rname); + + hdr[0] = 0; /* NULL of string termination */ + hdr[1] = 0; /* don't autoname */ + hdr[2] = 0; /* MSB of don't autoname */ + fwrite(hdr, 3, 1, mps_file); /* NULL string terminator + route autoname flag */ + + lat = maxlat / 180.0 * 2147483648.0; + lon = maxlon / 180.0 * 2147483648.0; + + le_write32(&lat, lat); + le_write32(&lon, lon); + + fwrite(&lat, 4, 1, mps_file); + fwrite(&lon, 4, 1, mps_file); + + if (maxalt == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&maxalt, 8 , 1, mps_file); + } + + lat = minlat / 180.0 * 2147483648.0; + lon = minlon / 180.0 * 2147483648.0; + + le_write32(&lat, lat); + le_write32(&lon, lon); + + fwrite(&lat, 4, 1, mps_file); + fwrite(&lon, 4, 1, mps_file); + + if (minalt == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + unsigned char cbuf[8]; + hdr[0] = 1; + + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&minalt, 8 , 1, mps_file); + } + + le_write32(&rte_datapoints, rte_datapoints); + fwrite(&rte_datapoints, 4, 1, mps_file); + } +} + +static void +mps_routehdr_w_wrapper(const route_head *rte) +{ + mps_routehdr_w(mps_file_out, mps_ver_out, rte); +} + + +/* + * write out to file a route datapoint + * MRCB + */ +static void +mps_routedatapoint_w(FILE *mps_file, int mps_ver, const waypoint *rtewpt) +{ + unsigned char hdr[10]; + int lat; + int lon; + time_t t = rtewpt->creation_time; + char zbuf[20]; + char ffbuf[20]; + char *src; + char *ident; + int reclen; + + int maxlat; + int maxlon; + int minlat; + int minlon; + double maxalt=unknown_alt; + double minalt=unknown_alt; + + double mps_altitude; + waypoint *wptfound; + + memset(zbuf, 0, sizeof(zbuf)); + memset(ffbuf, 0xff, sizeof(ffbuf)); + + if (prevRouteWpt != NULL) { + /* output the route link details */ + reclen = 2; + le_write32(&reclen, reclen); + fwrite(&reclen, 4, 1, mps_file); + + /* output end point 1 */ + lat = prevRouteWpt->latitude / 180.0 * 2147483648.0; + lon = prevRouteWpt->longitude / 180.0 * 2147483648.0; + le_write32(&lat, lat); + le_write32(&lon, lon); + + fwrite(&lat, 4, 1, mps_file); + fwrite(&lon, 4, 1, mps_file); + + mps_altitude = prevRouteWpt->altitude; + if (mps_altitude == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&mps_altitude, 8 , 1, mps_file); + } + + /* output end point 2 */ + lat = rtewpt->latitude / 180.0 * 2147483648.0; + lon = rtewpt->longitude / 180.0 * 2147483648.0; + le_write32(&lat, lat); + le_write32(&lon, lon); + + fwrite(&lat, 4, 1, mps_file); + fwrite(&lon, 4, 1, mps_file); + + mps_altitude = rtewpt->altitude; + if (mps_altitude == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&mps_altitude, 8 , 1, mps_file); + } + + if (rtewpt->latitude > prevRouteWpt->latitude) { + maxlat = rtewpt->latitude / 180.0 * 2147483648.0; + minlat = prevRouteWpt->latitude / 180.0 * 2147483648.0; + } + else { + minlat = rtewpt->latitude / 180.0 * 2147483648.0; + maxlat = prevRouteWpt->latitude / 180.0 * 2147483648.0; + } + + if (rtewpt->longitude > prevRouteWpt->longitude) { + maxlon = rtewpt->longitude / 180.0 * 2147483648.0; + minlon = prevRouteWpt->longitude / 180.0 * 2147483648.0; + } + else { + minlon = rtewpt->longitude / 180.0 * 2147483648.0; + maxlon = prevRouteWpt->longitude / 180.0 * 2147483648.0; + } + + if (rtewpt->altitude != unknown_alt) maxalt = rtewpt->altitude; + if (rtewpt->altitude != unknown_alt) minalt = rtewpt->altitude; + if (prevRouteWpt->altitude != unknown_alt) { + if ((prevRouteWpt->altitude > maxalt) || + (maxalt == unknown_alt)) maxalt = prevRouteWpt->altitude; + if ((prevRouteWpt->altitude < minalt) || + (minalt == unknown_alt)) minalt = prevRouteWpt->altitude; + } + + fwrite (zbuf, 1, 1, mps_file); + + /* output max coords of the link */ + le_write32(&maxlat, maxlat); + le_write32(&maxlon, maxlon); + + fwrite(&maxlat, 4, 1, mps_file); + fwrite(&maxlon, 4, 1, mps_file); + + if (maxalt == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&maxalt, 8 , 1, mps_file); + } + + /* output min coords of the link */ + le_write32(&minlat, minlat); + le_write32(&minlon, minlon); + + fwrite(&minlat, 4, 1, mps_file); + fwrite(&minlon, 4, 1, mps_file); + + if (minalt == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&minalt, 8 , 1, mps_file); + } + + } + + if(rtewpt->description) src = rtewpt->description; + if(rtewpt->notes) src = rtewpt->notes; + ident = global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, src) : + rtewpt->shortname; + + fputs(ident, mps_file); + fwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */ + + wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, ident); + if (wptfound != NULL) zbuf[0] = (char)MPSHIDDENROUTEWPTCLASS; + else zbuf[0] = (char)MPSDEFAULTWPTCLASS; + fwrite(zbuf, 4, 1, mps_file); /* class */ + + zbuf[0]=0; + fwrite(zbuf, 1, 1, mps_file); /* country - i.e. empty string */ + + if ((mps_ver == 4) || (mps_ver == 5)) { + fwrite(zbuf, 4, 1, mps_file); /* subclass part 1 */ + fwrite(ffbuf, 12, 1, mps_file); /* subclass part 2 */ + fwrite(zbuf, 2, 1, mps_file); /* subclass part 3 */ + fwrite(ffbuf, 4, 1, mps_file); /* unknown */ + + fwrite(zbuf, 1, 1, mps_file); + hdr[0] = 3; + fwrite(hdr, 1, 1, mps_file); + fwrite(zbuf, 17, 1, mps_file); + } + else { + fwrite(zbuf, 8, 1, mps_file); /* subclass part 1 */ + fwrite(ffbuf, 8, 1, mps_file); /* subclass part 2 */ + fwrite(zbuf, 1, 1, mps_file); /* subclass part 3 */ + + /* unknown */ + fwrite(zbuf, 1, 1, mps_file); + hdr[0] = 3; + fwrite(hdr, 1, 1, mps_file); + fwrite(zbuf, 16, 1, mps_file); + } + + prevRouteWpt = rtewpt; +} + +static void +mps_routedatapoint_w_wrapper(const waypoint *rte) +{ + mps_routedatapoint_w(mps_file_out, mps_ver_out, rte); +} + + +/* + * write out to file a route trailer + * MRCB + */ +static void +mps_routetrlr_w(FILE *mps_file, int mps_ver, const route_head *rte) +{ + char hdr[2]; + int value = 0; + + hdr[0] = 1; + + if (rte->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid route - treat as a placeholder for now */ + fwrite(&value, 4, 1, mps_file); + fwrite(hdr, 1, 1, mps_file); + } +} + +static void +mps_routetrlr_w_wrapper(const route_head *rte) +{ + mps_routetrlr_w(mps_file_out, mps_ver_out, rte); +} + + +/* + * read in from file a track record + * MRCB + */ +static void +mps_track_r(FILE *mps_file, int mps_ver, route_head **trk) +{ + char tbuf[100]; + char trkname[MPSNAMEBUFFERLEN]; + int lat; + int lon; + + int dateTime = 0; + route_head *track_head; + int trk_count; + + waypoint *thisWaypoint; + double mps_altitude = unknown_alt; + double mps_depth = unknown_alt; + + mps_readstr(mps_file, trkname, sizeof(trkname)); +#ifdef MPS_DEBUG + fprintf(stderr, "mps_track_r: reading track %s\n", trkname); +#endif + + + fread(tbuf, 1, 1, mps_file); /* display flag */ + fread(tbuf, 4, 1, mps_file); /* colour */ + + fread(&trk_count, 4, 1, mps_file); /* number of datapoints in tracklog */ + trk_count = le_read32(&trk_count); + + /* I don't know, but perhaps it's valid to have a track with no waypoints */ + /* Seems dumb, but truth is stranger than fiction. Of course, it could be */ + /* that there are more than MAXINT / 2 waypoints, yeah sure */ + /* Allow the caller the perform the file resync caused by bombing out early */ + if (trk_count < 0) return; +#ifdef MPS_DEBUG + fprintf(stderr, "mps_track_r: there are %d track waypoints %d\n", trk_count); +#endif + + track_head = route_head_alloc(); + track_head->rte_name = xstrdup(trkname); + track_add_head(track_head); + *trk = track_head; + + while (trk_count--) { + + fread(&lat, 4, 1, mps_file); + fread(&lon, 4, 1, mps_file); + lat = le_read32(&lat); + lon = le_read32(&lon); + + fread(tbuf, 1, 1, mps_file); /* altitude validity */ + if (tbuf[0] == 1) { + le_fread64(&mps_altitude,sizeof(mps_altitude),1,mps_file); + } + else { + mps_altitude = unknown_alt; + le_fread64(tbuf,sizeof(mps_altitude),1, mps_file); + } + + fread(tbuf, 1, 1, mps_file); /* date/time validity */ + if (tbuf[0] == 1) { + fread(&dateTime,sizeof(dateTime),1,mps_file); + } + else { + fread(tbuf,sizeof(dateTime),1, mps_file); + } + + fread(tbuf, 1, 1, mps_file); /* depth validity */ + if (tbuf[0] == 1) { + le_fread64(&mps_depth,sizeof(mps_depth),1,mps_file); + } + else { + mps_depth = unknown_alt; + le_fread64(tbuf,sizeof(mps_depth),1, mps_file); + } + + thisWaypoint = waypt_new(); + thisWaypoint->latitude = lat / 2147483648.0 * 180.0; + thisWaypoint->longitude = lon / 2147483648.0 * 180.0; + thisWaypoint->creation_time = le_read32(&dateTime); + thisWaypoint->centiseconds = 0; + thisWaypoint->altitude = mps_altitude; + thisWaypoint->depth = mps_depth; + route_add_wpt(track_head, thisWaypoint); + + } /* while (trk_count--) */ + + return; + +} + +/* + * write out to file a tracklog header + * MRCB + */ +static void +mps_trackhdr_w(FILE *mps_file, int mps_ver, const route_head *trk) +{ + unsigned int reclen; + unsigned int trk_datapoints; + unsigned int colour = 0; /* unknown colour */ + int tname_len; + char *tname; + char hdr[20]; + waypoint *testwpt; + time_t uniqueValue; + + queue *elem, *tmp; + + /* total nodes (waypoints) this track */ + trk_datapoints = 0; + if (trk->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid track - treat as a placeholder for now */ + QUEUE_FOR_EACH(&trk->waypoint_list, elem, tmp) { + if (trk_datapoints == 0) { + testwpt = (waypoint *)elem; + uniqueValue = testwpt->creation_time; + } + trk_datapoints++; + } + + if (uniqueValue == 0) { + uniqueValue = current_time(); + } + + /* track name */ + if (!trk->rte_name) { + sprintf(hdr, "Track%04x", uniqueValue); + tname = xstrdup(hdr); + } + else + tname = xstrdup(trk->rte_name); + + tname_len = strlen(tname); + reclen = tname_len + 11; /* "T" (1) + strlen(tname) + NULL (1) + display flag (1) + colour (4) + + num track datapoints value (4) */ + + reclen += (trk_datapoints * 31) - 1; /* lat (4) + lon (4) + alt (9) + date (5) + depth (9) ;*/ + /* -1 is because reclen starts from 0 which means a length of 1 */ + le_write32(&reclen, reclen); + fwrite(&reclen, 4, 1, mps_file); + + hdr[0] = 'T'; + fwrite(hdr, 1, 1, mps_file); + + fwrite(tname, tname_len, 1, mps_file); + xfree(tname); + + hdr[0] = 0; + hdr[1] = 1; + fwrite(hdr, 2, 1, mps_file); /* NULL string terminator + display flag */ + + le_write32(&colour, colour); + fwrite(&colour, 4, 1, mps_file); + + le_write32(&trk_datapoints, trk_datapoints); + fwrite(&trk_datapoints, 4, 1, mps_file); + } + +} + +static void +mps_trackhdr_w_wrapper(const route_head *trk) +{ + mps_trackhdr_w(mps_file_out, mps_ver_out, trk); +} + + +/* + * write out to file a tracklog datapoint + * MRCB + */ +static void +mps_trackdatapoint_w(FILE *mps_file, int mps_ver, const waypoint *wpt) +{ + unsigned char hdr[10]; + int lat = wpt->latitude / 180.0 * 2147483648.0; + int lon = wpt->longitude / 180.0 * 2147483648.0; + time_t t = wpt->creation_time; + char zbuf[10]; + + double mps_altitude = wpt->altitude; + double mps_depth = (mpsusedepth ? wpt->depth : unknown_alt); + + memset(zbuf, 0, sizeof(zbuf)); + + le_write32(&lat, lat); + le_write32(&lon, lon); + fwrite(&lat, 4, 1, mps_file); + fwrite(&lon, 4, 1, mps_file); + + if (mps_altitude == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&mps_altitude, 8 , 1, mps_file); + } + + if (t > 0) { /* a valid time is assumed to > 0 */ + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_write32(&t, t); + fwrite(&t, 4, 1, mps_file); + } + else { + fwrite(zbuf, 5, 1, mps_file); + } + + if (mps_depth == unknown_alt) { + fwrite(zbuf, 9, 1, mps_file); + } + else { + hdr[0] = 1; + fwrite(hdr, 1 , 1, mps_file); + le_fwrite64(&mps_depth, 8 , 1, mps_file); + } +} + +static void +mps_trackdatapoint_w_wrapper(const waypoint *wpt) +{ + mps_trackdatapoint_w(mps_file_out, mps_ver_out, wpt); +} + + +static void +mps_read(void) +{ + waypoint *wpt; + route_head *rte; + route_head *trk; + + char recType; + int reclen; + int morework; + unsigned int mpsWptClass; + long mpsFileInPos; + + mps_ver_in = 0; /* although initialised at declaration, what happens if there are two mapsource + input files? */ + mps_fileHeader_r(mps_file_in, &mps_ver_in); + +#ifdef DUMP_ICON_TABLE + printf("static icon_mapping_t garmin_icon_table[] = {\n"); +#endif + + morework = 1; + while (morework && !feof(mps_file_in)) { + + /* Read record length of next section */ + fread(&reclen, 4, 1, mps_file_in); + reclen = le_read32(&reclen); + + if (reclen < 0) fatal (MYNAME ": a record length read from the input file is invalid. \nEither the file is corrupt or unsupported"); + + /* Read the record type "flag" in - using fread in case in the future need more than one char */ + fread(&recType, 1, 1, mps_file_in); + mpsFileInPos = ftell(mps_file_in); + switch (recType) { + case 'W': + /* Waypoint record */ + /* With routes, we need the waypoint info that reveals, for example, the symbol type */ + mps_waypoint_r(mps_file_in, mps_ver_in, &wpt, &mpsWptClass); + +#ifdef MPS_DEBUG + fprintf(stderr,"Read a waypoint - %s\n", wpt->shortname); +#endif + + if (ftell(mps_file_in) != mpsFileInPos + reclen) { + /* should junk this record and not save it since we're out of sync with the file */ + /* Should and how do we warn the user? */ +#ifdef MPS_DEBUG + fprintf(stderr,"Lost sync with the file reading waypoint - %s\n", wpt->shortname); +#endif + fseek (mps_file_in, mpsFileInPos + reclen, SEEK_SET); + waypt_free( wpt ); + } + else { + /* only add to the "real" list if a "user" waypoint otherwise add to the private list */ + if (mpsWptClass == MPSDEFAULTWPTCLASS) waypt_add(wpt); + else { + mps_wpt_q_add(&read_route_wpt_head, wpt); + waypt_free( wpt ); + } +#ifdef DUMP_ICON_TABLE + printf("\t{ %4u, \"%s\" },\n", icon, wpt->shortname); +#endif + } + break; + + case 'R': + /* Route record */ + mps_route_r(mps_file_in, mps_ver_in, &rte); + if (ftell(mps_file_in) != mpsFileInPos + reclen) { + /* should junk this record and not save it since we're out of sync with the file */ + /* Should and how do we warn the user? */ +#ifdef MPS_DEBUG + fprintf(stderr,"Lost sync with the file reading route - %s\n", rte->rte_name); +#endif + fseek (mps_file_in, mpsFileInPos + reclen, SEEK_SET); + } + break; + + case 'T': + /* Track record */ + mps_track_r(mps_file_in, mps_ver_in, &trk); + if (ftell(mps_file_in) != mpsFileInPos + reclen) { + /* should junk this record and not save it since we're out of sync with the file */ + /* Should and how do we warn the user? */ +#ifdef MPS_DEBUG + fprintf(stderr,"Lost sync with the file reading track - %s\n", trk->rte_name); +#endif + fseek (mps_file_in, mpsFileInPos + reclen, SEEK_SET); + } + break; + + case 'L': + /* Map segment record */ + mps_mapsegment_r(mps_file_in, mps_ver_in); + if (ftell(mps_file_in) != mpsFileInPos + reclen) { + /* should junk this record and not save it since we're out of sync with the file */ + /* Should and how do we warn the user? */ + fseek (mps_file_in, mpsFileInPos + reclen, SEEK_SET); + } + break; + + case 'V': + /* Mapset record */ + mps_mapsetname_r(mps_file_in, mps_ver_in); + /* Last record in the file */ + morework = 0; + break; + default: + /* Unknown record type. Skip over it. */ + fseek(mps_file_in, reclen, SEEK_CUR); + } + + } /* while (!feof(mps_file_in)) */ + +#ifdef DUMP_ICON_TABLE + printf("\t{ -1, NULL },\n"); + printf("};\n"); +#endif + + return ; + +} + +void +mps_write(void) +{ + int short_length; + waypoint *wpt; + route_head *rte; + route_head *trk; + + char recType; + int reclen; + int reclen2; + unsigned int tocopy; + long tempFilePos; + unsigned int mpsWptClass; + + unsigned char copybuf[8192]; + + if (snlen) + short_length = atoi(snlen); + else + short_length = 10; + + if (mpsmergeout) { + /* need to skip over the merging header and test merge version */ + mps_fileHeader_r(mps_file_temp, &mps_ver_temp); + + if (mpsverout) { + if (mps_ver_temp != atoi(mpsverout)) { + /* Need to clean up after a junk version specified */ + /* close the real output file + renamed original output file */ + /* then delete the "real" file and rename the temporarily renamed file back */ + fclose(mps_file_temp); + fclose(mps_file_out); + remove(origname); + rename(tempname,origname); + fatal (MYNAME ": merge source version is %d, requested out version is %d\n", mps_ver_temp, atoi(mpsverout)); + } + } + else { + mpsverout = xmalloc(10); + sprintf(mpsverout,"%d", mps_ver_temp); + } + } + + if (mpsverout) + mps_ver_out = atoi(mpsverout); + else + mps_ver_out = 5; + + mkshort_handle = mkshort_new_handle(); + + setshort_length(mkshort_handle, short_length); + + if (snwhiteopt) + setshort_whitespace_ok(mkshort_handle, atoi(snwhiteopt)); + else + setshort_whitespace_ok(mkshort_handle, 0); + + mps_fileHeader_w(mps_file_out, mps_ver_out); + + /* .mps file order is wpts, rtes, trks then mapsets. If we've not been asked to write + wpts, but we are merging, then read in the waypoints from the original file and + write them out, prior to doing rtes. + */ + /* if ((mpsmergeout) && (global_opts.objective != wptdata)) { */ + if ((mpsmergeout) && (! doing_wpts)) { + while (!feof(mps_file_temp)) { + + fread(&reclen, 4, 1, mps_file_temp); + reclen2 = le_read32(&reclen); + + /* Read the record type "flag" in - using fread in case in the future need more than one char */ + fread(&recType, 1, 1, mps_file_temp); + + if (recType == 'W') { + fwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */ + fwrite(&recType, 1, 1, mps_file_out); + + tempFilePos = ftell(mps_file_temp); + /* need to read in the waypoint info only because later we may need to check for uniqueness + since we're here because the user didn't request waypoints, this should be acceptable */ + mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt, &mpsWptClass); + mps_wpt_q_add(&written_wpt_head, wpt); + waypt_free( wpt ); + /* now return to the start of the waypoint data to do a "clean" copy */ + fseek(mps_file_temp, tempFilePos, SEEK_SET); + + /* copy the data using a "reasonably" sized buffer */ + for(tocopy = reclen2; tocopy > 0; tocopy -= sizeof(copybuf)) { + fread(copybuf, (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy), 1, mps_file_temp); + fwrite(copybuf, (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy), 1, mps_file_out); + } + } + else break; + } /* while (!feof(mps_file_temp)) */ + } /* if (mpsmergeout) */ + + /* irrespective of merging, now write out any waypoints */ + /* if (global_opts.objective == wptdata) { */ + if (doing_wpts) { + + if (mpsmergeout) { + /* since we're processing waypoints, we should read in from whatever version and write out */ + /* in the selected version */ + while (!feof(mps_file_temp)) { + + fread(&reclen, 4, 1, mps_file_temp); + reclen2 = le_read32(&reclen); + + /* Read the record type "flag" in - using fread in case in the future need more than one char */ + fread(&recType, 1, 1, mps_file_temp); + + if (recType == 'W') { + /* need to be careful that we aren't duplicating a wpt defined from elsewhere */ + mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt, &mpsWptClass); + if (mpsWptClass == MPSDEFAULTWPTCLASS) waypt_add(wpt);else waypt_free(wpt); + } + else break; + } + } + waypt_disp_all(mps_waypoint_w_unique_wrapper); + } + + /* prior to writing any tracks as requested, if we're doing a merge, read in the rtes + from the original file and then write them out, ready for tracks to follow + */ + /* if ((mpsmergeout) && (global_opts.objective != rtedata)) { */ + if ((mpsmergeout) && (! doing_rtes)) { + while (!feof(mps_file_temp)) { + + /* this might all fail if the relevant waypoints haven't been written */ + if (recType == 'R') { + fwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */ + fwrite(&recType, 1, 1, mps_file_out); + + for(tocopy = reclen2; tocopy > 0; tocopy -= sizeof(copybuf)) { + fread(copybuf, (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy), 1, mps_file_temp); + fwrite(copybuf, (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy), 1, mps_file_out); + } + } + else break; + fread(&reclen, 4, 1, mps_file_temp); + reclen2 = le_read32(&reclen); + + /* Read the record type "flag" in - using fread in case in the future need more than one char */ + fread(&recType, 1, 1, mps_file_temp); + + } /* while (!feof(mps_file_temp)) */ + } /* if (mpsmergeout) */ + + /* routes are next in the wpts, rtes, trks, mapset sequence */ + /* if (global_opts.objective == rtedata) { */ + if (doing_rtes) { + + if (mpsmergeout) { + /* since we're processing routes, we should read in from whatever version and write out */ + /* in the selected version */ + while (!feof(mps_file_temp)) { + + if (recType == 'R') { + mps_route_r(mps_file_temp, mps_ver_temp, &rte); + } + else break; + + fread(&reclen, 4, 1, mps_file_temp); + reclen2 = le_read32(&reclen); + + /* Read the record type "flag" in - using fread in case in the future need more than one char */ + fread(&recType, 1, 1, mps_file_temp); + } + } + /* need to make sure there is a "real" waypoint for each route waypoint + Need to be careful about creating duplicate wpts as MapSource chokes on these + so, if the user requested waypoints to be output too, then write the route + waypoints only if unique in the total list of waypoints ("real" and route derived) + If the user didn't request waypoints to be output, then output the route derived + waypoints without consideration for uniqueness for "real" waypoints that haven't + been output (phew!) + */ + route_disp_all(mps_noop, mps_noop, mps_route_wpt_w_unique_wrapper); + + route_disp_all(mps_routehdr_w_wrapper, mps_routetrlr_w_wrapper, mps_routedatapoint_w_wrapper); + } + + /* If merging but we haven't been requested to write out tracks, then read in tracks from + the original file and write these out prior to any mapset writes later on + */ + /* if ((mpsmergeout) && (global_opts.objective != trkdata)) { */ + if ((mpsmergeout) && (! doing_trks)) { + while (!feof(mps_file_temp)) { + + if (recType == 'T') { + fwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */ + fwrite(&recType, 1, 1, mps_file_out); + + for(tocopy = reclen2; tocopy > 0; tocopy -= sizeof(copybuf)) { + fread(copybuf, (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy), 1, mps_file_temp); + fwrite(copybuf, (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy), 1, mps_file_out); + } + } + else break; + fread(&reclen, 4, 1, mps_file_temp); + reclen2 = le_read32(&reclen); + + /* Read the record type "flag" in - using fread in case in the future need more than one char */ + fread(&recType, 1, 1, mps_file_temp); + + } /* while (!feof(mps_file_temp)) */ + } /* if (mpsmergeout) */ + + /* tracks are next in the wpts, rte, trks, mapset sequence in .mps files */ + /* if (global_opts.objective == trkdata) { */ + if (doing_trks) { + if (mpsmergeout) { + /* since we're processing tracks, we should read in from whatever version and write out + in the selected version */ + while (!feof(mps_file_temp)) { + + if (recType == 'T') { + mps_track_r(mps_file_temp, mps_ver_temp, &trk); + } + else break; + + fread(&reclen, 4, 1, mps_file_temp); + reclen2 = le_read32(&reclen); + + /* Read the record type "flag" in - using fread in case in the future need more than one char */ + fread(&recType, 1, 1, mps_file_temp); + } + } + track_disp_all(mps_trackhdr_w_wrapper, mps_noop, mps_trackdatapoint_w_wrapper); + } + + if (mpsmergeout) { + /* should now be reading a either a map segment or a mapset - since we would write out an empty one, + let's use the one from the merge file which may well have decent data in */ + for (;;) { + fwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */ + fwrite(&recType, 1, 1, mps_file_out); + + for(tocopy = reclen2; tocopy > 0; tocopy -= sizeof(copybuf)) { + fread(copybuf, (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy), 1, mps_file_temp); + fwrite(copybuf, (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy), 1, mps_file_out); + } + if (recType != 'V') { + fread(&reclen, 4, 1, mps_file_temp); + reclen2 = le_read32(&reclen); + + /* Read the record type "flag" in - using fread in case in the future need more than one char */ + fread(&recType, 1, 1, mps_file_temp); + } + else break; + } + + } + else mps_mapsetname_w(mps_file_out, mps_ver_out); + + mkshort_del_handle(mkshort_handle); + +} + +ff_vecs_t mps_vecs = { + ff_type_file, + mps_rd_init, + mps_wr_init, + mps_rd_deinit, + mps_wr_deinit, + mps_read, + mps_write, + NULL, + mps_args +}; diff --git a/mingw/Makefile b/mingw/Makefile new file mode 100644 index 000000000..f5833cb7d --- /dev/null +++ b/mingw/Makefile @@ -0,0 +1,26 @@ +CC=/usr/local/cross-tools/bin/i386-mingw32msvc-gcc +VPATH=..:../shapelib + +FILES=gpsbabel.exe libexpat.dll ../win32/gpsbabelfront.exe ../README* ../COPYING + +gpsbabel.exe: wintesto.cmd + +include ../Makefile +CFLAGS=-Iinclude -I../coldsync -O $(INHIBIT_USB) +# +# Must define empty (don't comment out the whole line) if you want to +# override INHIBIT_USB from the parent Makefile. +# +INHIBIT_USB=#-DNO_USB +OSJEEPS=jeeps/gpsusbwin.o + +gpsbabel.exe: $(OBJS) + $(CC) -static $(CFLAGS) $(OBJS) lib/libexpat.a -o gpsbabel.exe -lsetupapi + zip -j /tmp/gpsbabel-$(VERSIOND).zip $(FILES) + cp gpsbabel.exe /tmp + +mkwintesto: mkwintesto.c + /usr/bin/cc mkwintesto.c -o mkwintesto + +wintesto.cmd: mkwintesto + ./mkwintesto ../testo diff --git a/mingw/README.expat b/mingw/README.expat new file mode 100644 index 000000000..ae51d66ca --- /dev/null +++ b/mingw/README.expat @@ -0,0 +1 @@ +This expat library comes from http://sourceforge.net/projects/mingwrep/ diff --git a/mingw/coldsync/.ignore b/mingw/coldsync/.ignore new file mode 100644 index 000000000..e69de29bb diff --git a/mingw/include/expat.h b/mingw/include/expat.h new file mode 100644 index 000000000..5fdab9c72 --- /dev/null +++ b/mingw/include/expat.h @@ -0,0 +1,713 @@ +/* +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +#ifndef XmlParse_INCLUDED +#define XmlParse_INCLUDED 1 + +#include + +#ifndef XMLPARSEAPI +# ifdef __declspec +# define XMLPARSEAPI __declspec(dllimport) +# else +# define XMLPARSEAPI /* nothing */ +# endif +#endif /* not defined XMLPARSEAPI */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *XML_Parser; + +/* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + const XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ + +typedef void (*XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +void XMLPARSEAPI +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* + The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" keyword. + The "isrequired" parameter will be true and the default value will + be NULL in the case of "#REQUIRED". If "isrequired" is true and + default is non-NULL, then this is a "#FIXED" default. + */ + +typedef void (*XML_AttlistDeclHandler) (void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +void XMLPARSEAPI +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + + + /* The XML declaration handler is called for *both* XML declarations and + text declarations. The way to distinguish is that the version parameter + will be null for text declarations. The encoding parameter may be null + for XML declarations. The standalone parameter will be -1, 0, or 1 + indicating respectively that there was no standalone parameter in + the declaration, that it was given as no, or that it was given as yes. + */ + +typedef void (*XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +void XMLPARSEAPI +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(*malloc_fcn)(size_t size); + void *(*realloc_fcn)(void *ptr, size_t size); + void (*free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the external +protocol or null if there is none specified. */ + +XML_Parser XMLPARSEAPI +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type names +and attribute names that belong to a namespace will be expanded; +unprefixed attribute names are never expanded; unprefixed element type +names are expanded only if there is a default namespace. The expanded +name is the concatenation of the namespace URI, the namespace separator character, +and the local part of the name. If the namespace separator is '\0' then +the namespace URI and the local part will be concatenated without any +separator. When a namespace is not declared, the name and prefix will be +passed through without expansion. */ + +XML_Parser XMLPARSEAPI +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suit referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ + +XML_Parser XMLPARSEAPI +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. */ + +typedef void (*XML_StartElementHandler)(void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (*XML_EndElementHandler)(void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (*XML_CharacterDataHandler)(void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (*XML_ProcessingInstructionHandler)(void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data); + +typedef void (*XML_StartCdataSectionHandler)(void *userData); +typedef void (*XML_EndCdataSectionHandler)(void *userData); + +/* This is called for any characters in the XML document for +which there is no applicable handler. This includes both +characters that are part of markup which is of a kind that is +not reported (comments, markup declarations), or characters +that are part of a construct which could be reported but +for which no handler has been supplied. The characters are passed +exactly as they were in the XML document except that +they will be encoded in UTF-8. Line boundaries are not normalized. +Note that a byte order mark character is not passed to the default handler. +There are no guarantees about how characters are divided between calls +to the default handler: for example, a comment might be split between +multiple calls. */ + +typedef void (*XML_DefaultHandler)(void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. */ + +typedef void (*XML_StartDoctypeDeclHandler)(void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset + ); + +/* This is called for the start of the DOCTYPE declaration when the +closing > is encountered, but after processing any external subset. */ +typedef void (*XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (), value will + be non-null and systemId, publicID, and notationName will be null. + The value string is NOT null terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be null and systemId will be non-null. + The publicId argument will be null unless a public identifier was + provided. The notationName argument will have a non-null value only + for unparsed entity declarations. +*/ + +typedef void (*XML_EntityDeclHandler) (void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +void XMLPARSEAPI +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. +This is called for a declaration of an unparsed (NDATA) +entity. The base argument is whatever was set by XML_SetBase. +The entityName, systemId and notationName arguments will never be null. +The other arguments may be. */ + +typedef void (*XML_UnparsedEntityDeclHandler)(void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. +The base argument is whatever was set by XML_SetBase. +The notationName will never be null. The other arguments can be. */ + +typedef void (*XML_NotationDeclHandler)(void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for +each namespace declaration. The call to the start and end element +handlers occur between the calls to the start and end namespace +declaration handlers. For an xmlns attribute, prefix will be null. +For an xmlns="" attribute, uri will be null. */ + +typedef void (*XML_StartNamespaceDeclHandler)(void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (*XML_EndNamespaceDeclHandler)(void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone (it has an +external subset or a reference to a parameter entity, but does not +have standalone="yes"). If this handler returns 0, then processing +will not continue, and the parser will return a +XML_ERROR_NOT_STANDALONE error. */ + +typedef int (*XML_NotStandaloneHandler)(void *userData); + +/* This is called for a reference to an external parsed general entity. +The referenced entity is not automatically parsed. +The application can parse it immediately or later using +XML_ExternalEntityParserCreate. +The parser argument is the parser parsing the entity containing the reference; +it can be passed as the parser argument to XML_ExternalEntityParserCreate. +The systemId argument is the system identifier as specified in the entity declaration; +it will not be null. +The base argument is the system identifier that should be used as the base for +resolving systemId if systemId was relative; this is set by XML_SetBase; +it may be null. +The publicId argument is the public identifier as specified in the entity declaration, +or null if none was specified; the whitespace in the public identifier +will have been normalized as required by the XML spec. +The context argument specifies the parsing context in the format +expected by the context argument to +XML_ExternalEntityParserCreate; context is valid only until the handler +returns, so if the referenced entity is to be parsed later, it must be copied. +The handler should return 0 if processing should not continue because of +a fatal error in the handling of the external entity. +In this case the calling parser will return an XML_ERROR_EXTERNAL_ENTITY_HANDLING +error. +Note that unlike other handlers the first argument is the parser, not userData. */ + +typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This structure is filled in by the XML_UnknownEncodingHandler +to provide information to the parser about encodings that are unknown +to the parser. +The map[b] member gives information about byte sequences +whose first byte is b. +If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar value c. +If map[b] is -1, then the byte sequence is malformed. +If map[b] is -n, where n >= 2, then b is the first byte of an n-byte +sequence that encodes a single Unicode scalar value. +The data member will be passed as the first argument to the convert function. +The convert function is used to convert multibyte sequences; +s will point to a n-byte sequence where map[(unsigned char)*s] == -n. +The convert function must return the Unicode scalar value +represented by this byte sequence or -1 if the byte sequence is malformed. +The convert function may be null if the encoding is a single-byte encoding, +that is if map[b] >= -1 for all bytes b. +When the parser is finished with the encoding, then if release is not null, +it will call release passing it the data member; +once release has been called, the convert function will not be called again. + +Expat places certain restrictions on the encodings that are supported +using this mechanism. + +1. Every ASCII character that can appear in a well-formed XML document, +other than the characters + + $@\^`{}~ + +must be represented by a single byte, and that byte must be the +same byte that represents that character in ASCII. + +2. No character may require more than 4 bytes to encode. + +3. All characters encoded must have Unicode scalar values <= 0xFFFF, +(ie characters that would be encoded by surrogates in UTF-16 +are not allowed). Note that this restriction doesn't apply to +the built-in support for UTF-8 and UTF-16. + +4. No Unicode character may be encoded by more than one distinct sequence +of bytes. */ + +typedef struct { + int map[256]; + void *data; + int (*convert)(void *data, const char *s); + void (*release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. +The encodingHandlerData argument is that which was passed as the +second argument to XML_SetUnknownEncodingHandler. +The name argument gives the name of the encoding as specified in +the encoding declaration. +If the callback can provide information about the encoding, +it must fill in the XML_Encoding structure, and return 1. +Otherwise it must return 0. +If info does not describe a suitable encoding, +then the parser will return an XML_UNKNOWN_ENCODING error. */ + +typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +void XMLPARSEAPI +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +void XMLPARSEAPI +XML_SetStartElementHandler(XML_Parser, XML_StartElementHandler); + +void XMLPARSEAPI +XML_SetEndElementHandler(XML_Parser, XML_EndElementHandler); + +void XMLPARSEAPI +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +void XMLPARSEAPI +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +void XMLPARSEAPI +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +void XMLPARSEAPI +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +void XMLPARSEAPI +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +void XMLPARSEAPI +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of internal entities. +The entity reference will be passed to the default handler. */ + +void XMLPARSEAPI +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of internal entities. +The entity reference will not be passed to the default handler. */ + +void XMLPARSEAPI +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +void XMLPARSEAPI +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +void XMLPARSEAPI +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +void XMLPARSEAPI +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +void XMLPARSEAPI +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +void XMLPARSEAPI +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +void XMLPARSEAPI +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +void XMLPARSEAPI +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +void XMLPARSEAPI +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +void XMLPARSEAPI +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +void XMLPARSEAPI +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-null value for arg is specified here, then it will be passed +as the first argument to the external entity ref handler instead +of the parser object. */ +void XMLPARSEAPI +XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg); + +void XMLPARSEAPI +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end element, +processing instruction or character data. It causes the corresponding +markup to be passed to the default handler. */ +void XMLPARSEAPI +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single + string separated by the separator character specified when the parser + was created: URI + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the names + has a prefix. +*/ + +void XMLPARSEAPI +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +void XMLPARSEAPI +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or null. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument +to XML_ParserCreate. It must not be called after XML_Parse +or XML_ParseBuffer. */ + +int XMLPARSEAPI +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed +as the first argument to callbacks instead of userData. +The userData will still be accessible using XML_GetUserData. */ + +void XMLPARSEAPI +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* Sets the base to be used for resolving relative URIs in system identifiers in +declarations. Resolving relative identifiers is left to the application: +this value will be passed through as the base argument to the +XML_ExternalEntityRefHandler, XML_NotationDeclHandler +and XML_UnparsedEntityDeclHandler. The base argument will be copied. +Returns zero if out of memory, non-zero otherwise. */ + +int XMLPARSEAPI +XML_SetBase(XML_Parser parser, const XML_Char *base); + +const XML_Char XMLPARSEAPI * +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call +to the XML_StartElementHandler that were specified in the start-tag +rather than defaulted. Each attribute/value pair counts as 2; thus +this correspondds to an index into the atts array passed to the +XML_StartElementHandler. */ + +int XMLPARSEAPI +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to +XML_StartElementHandler, or -1 if there is no ID attribute. Each +attribute/value pair counts as 2; thus this correspondds to an index +into the atts array passed to the XML_StartElementHandler. */ + +int XMLPARSEAPI +XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns 0 if a fatal error is detected. +The last call to XML_Parse must have isFinal true; +len may be zero for this call (or any other). */ +int XMLPARSEAPI +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +void XMLPARSEAPI * +XML_GetBuffer(XML_Parser parser, int len); + +int XMLPARSEAPI +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Creates an XML_Parser object that can parse an external general entity; +context is a '\0'-terminated string specifying the parse context; +encoding is a '\0'-terminated string giving the name of the externally specified encoding, +or null if there is no externally specified encoding. +The context string consists of a sequence of tokens separated by formfeeds (\f); +a token consisting of a name specifies that the general entity of the name +is open; a token of the form prefix=uri specifies the namespace for a particular +prefix; a token of the form =uri specifies the default namespace. +This can be called at any point after the first call to an ExternalEntityRefHandler +so longer as the parser has not yet been freed. +The new parser is completely independent and may safely be used in a separate thread. +The handlers and userData are initialized from the parser argument. +Returns 0 if out of memory. Otherwise returns a new XML_Parser object. */ +XML_Parser XMLPARSEAPI +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD +subset). If parsing of parameter entities is enabled, then references +to external parameter entities (including the external DTD subset) +will be passed to the handler set with +XML_SetExternalEntityRefHandler. The context passed will be 0. +Unlike external general entities, external parameter entities can only +be parsed synchronously. If the external parameter entity is to be +parsed, it must be parsed during the call to the external entity ref +handler: the complete sequence of XML_ExternalEntityParserCreate, +XML_Parse/XML_ParseBuffer and XML_ParserFree calls must be made during +this call. After XML_ExternalEntityParserCreate has been called to +create the parser for the external parameter entity (context must be 0 +for this call), it is illegal to make any calls on the old parser +until XML_ParserFree has been called on the newly created parser. If +the library has been compiled without support for parameter entity +parsing (ie without XML_DTD being defined), then +XML_SetParamEntityParsing will return 0 if parsing of parameter +entities is requested; otherwise it will return non-zero. */ + +int XMLPARSEAPI +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE +}; + +/* If XML_Parse or XML_ParseBuffer have returned 0, then XML_GetErrorCode +returns information about the error. */ + +enum XML_Error XMLPARSEAPI +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse location. +They may be called when XML_Parse or XML_ParseBuffer return 0; +in this case the location is the location of the character at which +the error was detected. +They may also be called from any other callback called to report +some parse event; in this the location is the location of the first +of the sequence of characters that generated the event. */ + +int XMLPARSEAPI XML_GetCurrentLineNumber(XML_Parser parser); +int XMLPARSEAPI XML_GetCurrentColumnNumber(XML_Parser parser); +long XMLPARSEAPI XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. +Returns 0 if the event is in an internal entity. */ + +int XMLPARSEAPI +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a null pointer. Also returns a null pointer if a parse isn't active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. */ + +const char XMLPARSEAPI * +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees memory used by the parser. */ +void XMLPARSEAPI +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +const XML_LChar XMLPARSEAPI * +XML_ErrorString(int code); + +/* Return a string containing the version number of this expat */ +const XML_LChar XMLPARSEAPI * +XML_ExpatVersion(); + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlParse_INCLUDED */ diff --git a/mingw/jeeps/.ignore b/mingw/jeeps/.ignore new file mode 100644 index 000000000..e69de29bb diff --git a/mingw/lib/libexpat.a b/mingw/lib/libexpat.a new file mode 100644 index 0000000000000000000000000000000000000000..d4a3982bf3dcbb6586b187bf41f59c5c5dc543f4 GIT binary patch literal 39988 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 literal 0 HcmV?d00001 diff --git a/mingw/libexpat.dll b/mingw/libexpat.dll new file mode 100644 index 0000000000000000000000000000000000000000..e9a766c1bd445aa812fa384fc3233cc09b070ac2 GIT binary patch literal 122773 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 Qrp~r;Lqk&8%A!X84_$UALI3~& literal 0 HcmV?d00001 diff --git a/mingw/mkwintesto.c b/mingw/mkwintesto.c new file mode 100644 index 000000000..4a811f59a --- /dev/null +++ b/mingw/mkwintesto.c @@ -0,0 +1,456 @@ +/* + File for "converting" GPSBabel's testo shell script into + MS Windows NT/2000/XP command script. + + It is limited to: + - testo using the shell variable PNAME for the executable program being tested + - testo using ${TMPDIR} for the temporary directory in which test files are created + - testo using compare as the name of a shell function for comparing test results + - no other shell script conversion is performed apart from whole line comments; + unconverted script is discarded, not even included as comments in the output + + Copyright (C) 2003 Mark Bradley, mrcb.sf.gpsb@osps.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + */ + + +#include +#include +#include + +#define LINELENGTH 200 +#define MYNAME "MkWinTesto" + +/* ------------------------------------------------------------------------------------ */ +int f_outputLine ( + FILE *pfWhere, + char *pcWhat) +{ + int iLength; + int iThisChar; + + /* =========================== + Return 0 = output has new line + Return 1 = line ended on \ for continuation and no new line + */ + + iLength = strlen(pcWhat); + if (iLength > 2) { + if ((*(pcWhat+iLength-3) == '\\') && + (*(pcWhat+iLength-2) == '\r') && + (*(pcWhat+iLength-1) == '\n')) { + + for (iThisChar=0; iThisChar < iLength-3; iThisChar++) + fputc(*(pcWhat+iThisChar), pfWhere); + return 1; + } + } + if (iLength > 1) { + if ((*(pcWhat+iLength-2) == '\\') && + (*(pcWhat+iLength-1) == '\n')) { + + for (iThisChar=0; iThisChar < iLength-2; iThisChar++) + fputc(*(pcWhat+iThisChar), pfWhere); + return 1; + } + } + if (iLength > 0) { + if (*(pcWhat+iLength-1) == '\\') { + + for (iThisChar=0; iThisChar < iLength-1; iThisChar++) + fputc(*(pcWhat+iThisChar), pfWhere); + return 1; + } + } + + fputs(pcWhat, pfWhere); + fputs("\r\n", pfWhere); + return 0; +} + +/* ------------------------------------------------------------------------------------ */ +void +fatal(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +/* ------------------------------------------------------------------------------------ */ +int main( +int argc, + char *argv[]) +{ + char acLineIn[LINELENGTH]; + char acLineOut[LINELENGTH]; + char *pcTerm; + + int iThisChar; + int iStart; + int iTarget; + int iTranslateQuotes; + int iQuoteCount; + int iPrevLineContinues = 0; + int iEchoLevel = 0; + + FILE *pfTestoIn; + FILE *pfTestoOut; + + /* =========================== */ + + if (argc < 2) { + fatal(MYNAME ": needs a single parameter, the (testo) file to convert\n"); + } + pfTestoIn = fopen(argv[1], "rb"); + + if (pfTestoIn == NULL) { + fatal(MYNAME ": %s for reading\n",argv[1]); + } + else { + pfTestoOut = fopen ("wintesto.cmd", "wb"); + if (pfTestoOut == NULL) { + fatal (MYNAME ": wintesto.cmd for writing\n"); + } + else { + + /* Output the .CMD preamble */ + f_outputLine(pfTestoOut, "@echo off"); + f_outputLine(pfTestoOut, "REM"); + f_outputLine(pfTestoOut, "REM Simple Windows NT/2000/XP .cmd version of GPSBabel testo script"); + f_outputLine(pfTestoOut, "REM"); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, "SET TMPDIR=%TEMP%\\WINTESTO"); + f_outputLine(pfTestoOut, "MKDIR %TMPDIR% 2>NUL:"); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, "GOTO :REALSTART"); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, "REM =================================="); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, ":CommonCOMPARE"); + f_outputLine(pfTestoOut, "SET PARAM1=%2"); + f_outputLine(pfTestoOut, "SET PARAM2=%3"); + f_outputLine(pfTestoOut, "REM Test if param3 was a dir rather than a file, if so add a \\* to make fc work"); + f_outputLine(pfTestoOut, "FOR %%A IN (%3) DO IF \"d--------\"==\"%%~aA\" SET PARAM2=%3\\*"); + f_outputLine(pfTestoOut, "FOR /f \"delims=\" %%a IN ('fc %PARAM1% %PARAM2%') DO IF \"x%%a\"==\"xFC: no differences encountered\" GOTO :EOF"); + f_outputLine(pfTestoOut, "REM Show the first 5 lines of difference"); + f_outputLine(pfTestoOut, "fc %1 /LB5 %PARAM1% %PARAM2%"); + f_outputLine(pfTestoOut, "ECHO %* are not the same (first 5 differences above) - pausing. ^C to quit if required"); + f_outputLine(pfTestoOut, "PAUSE"); + f_outputLine(pfTestoOut, "GOTO :EOF"); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, "REM =================================="); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, ":COMPARE"); + f_outputLine(pfTestoOut, "CALL :CommonCOMPARE /L %1 %2"); + f_outputLine(pfTestoOut, "GOTO :EOF"); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, "REM =================================="); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, ":BINCOMPARE"); + f_outputLine(pfTestoOut, "CALL :CommonCOMPARE /B %1 %2"); + f_outputLine(pfTestoOut, "GOTO :EOF"); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, "REM =================================="); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, ":SORTandCOMPARE"); + f_outputLine(pfTestoOut, "SORT <%1 >%TMPDIR%\\s1"); + f_outputLine(pfTestoOut, "SORT <%2 >%TMPDIR%\\s2"); + f_outputLine(pfTestoOut, "CALL :COMPARE %TMPDIR%\\s1 %TMPDIR%\\s2"); + f_outputLine(pfTestoOut, "GOTO :EOF"); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, "REM =================================="); + f_outputLine(pfTestoOut, ""); + f_outputLine(pfTestoOut, ":REALSTART"); + f_outputLine(pfTestoOut, ""); + + + + while (! feof(pfTestoIn)) { + /* Read in the next line or stop if done */ + fgets(acLineIn, LINELENGTH-1, pfTestoIn); + if (acLineIn == NULL) break; + + /* Is the whole line a comment? Replace the hash with REM and output the rest */ + if (acLineIn[0] == '#') { + acLineOut[0]='\0'; + strcat (acLineOut,"REM"); + iTarget = 3; + + /* Add a space after the REM if the next char in the source isn't space */ + /* We're trying to preserve the original as much as possible */ + if (acLineIn[1] != ' ') { + strcat (acLineOut, " "); + iTarget++; + } + + /* Strip out any ending new lines */ + for (iThisChar=1; iThisChar 0) { + f_outputLine(pfTestoOut, "@echo off"); + f_outputLine(pfTestoOut, "@echo."); + iEchoLevel = 0; + } + iPrevLineContinues = f_outputLine(pfTestoOut, acLineOut); + } /* Is the whole line a comment? */ + + /* Are we near the top of testo where the program variable is defined? */ + else if (strncmp("PNAME=${PNAME:-",acLineIn,15) == 0) { + acLineOut[0]='\0'; + strcat (acLineOut,"SET PNAME="); + /* Copy the rest of the PNAME assignment stopping at a close } or EOL */ + for (iThisChar=15; iThisChar 0) { + f_outputLine(pfTestoOut, "@echo off"); + f_outputLine(pfTestoOut, "@echo."); + iEchoLevel = 0; + } + iPrevLineContinues = f_outputLine(pfTestoOut, acLineOut); + if (iPrevLineContinues == 1) f_outputLine(pfTestoOut, ""); + iPrevLineContinues = f_outputLine(pfTestoOut, "IF NOT EXIST %PNAME% ECHO Can't find %PNAME%&& GOTO :EOF"); + /* fputs("\r\n"); */ + } /* Are we near the top of testo where the program variable is defined? */ + + else { + /* Every other line.... */ + iStart = 0; + iTarget = 0; + iTranslateQuotes = 0; + iQuoteCount = 0; + acLineOut[0] = '\0'; + + /* Is this one of the test sequences mostly (all?) starting with a cleanup? */ + if (strncmp("rm -f ",acLineIn,6) == 0) { + if (iEchoLevel > 0) { + f_outputLine(pfTestoOut, "@echo off"); + f_outputLine(pfTestoOut, "@echo."); + iEchoLevel = 0; + } + iStart = 6; + strcat(acLineOut, "DEL "); + iTarget = 4; + } + /* Is this one of the test sequences where the program is run? */ + if (strncmp("${PNAME} ",acLineIn,9) == 0) { + iStart = 9; + iEchoLevel++; + strcat(acLineOut, "%PNAME% "); + iTarget = 8; + } + /* Is this one of the test sequences where we compare the rest? */ + if (strncmp("compare ",acLineIn,8) == 0) { + if (iEchoLevel > 0) { + f_outputLine(pfTestoOut, "@echo off"); + f_outputLine(pfTestoOut, "@echo."); + iEchoLevel = 0; + } + iStart = 8; + strcat(acLineOut, "CALL :COMPARE "); + iTarget = 14; + } + /* Is this one of the test sequences where we compare the rest? */ + if (strncmp("bincompare ",acLineIn,11) == 0) { + if (iEchoLevel > 0) { + f_outputLine(pfTestoOut, "@echo off"); + f_outputLine(pfTestoOut, "@echo."); + iEchoLevel = 0; + } + iStart = 11; + strcat(acLineOut, "CALL :BINCOMPARE "); + iTarget = 17; + } + /* Is this one of the test sequences where we compare the rest? */ + if (strncmp("sort_and_compare ",acLineIn,17) == 0) { + if (iEchoLevel > 0) { + f_outputLine(pfTestoOut, "@echo off"); + f_outputLine(pfTestoOut, "@echo."); + iEchoLevel = 0; + } + iStart = 17; + strcat(acLineOut, "CALL :SORTandCOMPARE "); + iTarget = 21; + } + /* Is this one of the test sequences where we prepare some data? */ + if (strncmp("echo \"",acLineIn,6) == 0) { + if (iEchoLevel > 0) { + f_outputLine(pfTestoOut, "@echo off"); + f_outputLine(pfTestoOut, "@echo."); + iEchoLevel = 0; + } + iStart = 6; + strcat(acLineOut, "ECHO "); + iTarget = 5; + iTranslateQuotes = 1; + iQuoteCount = 1; + } + /* Is this one of the test sequences where we prepare some data by using sed? */ + /* we only cater for sed that removes lines - this is only windows after all */ + if (strncmp("sed '/^L",acLineIn,8) == 0) { + pcTerm = strstr(acLineIn+8,"/d'"); + + /* Did we find a terminator in the string? */ + if ((pcTerm != NULL) && ((pcTerm - acLineIn) < LINELENGTH)) { + if (iEchoLevel > 0) { + f_outputLine(pfTestoOut, "@echo off"); + f_outputLine(pfTestoOut, "@echo."); + iEchoLevel = 0; + } + iStart = 8; + strcat(acLineOut, "FINDSTR /V \""); + iTarget = 12; + for (iThisChar=8; iThisChar<(pcTerm - acLineIn); iThisChar++) { + acLineOut[iTarget++] = acLineIn[iStart++]; + } + acLineOut[iTarget++] = (char)0; + strcat(acLineOut, "\""); + iStart += 3; /* skip over the terminator of the sed command */ + } /* Did we find a terminator in the string? */ + } + if ((iStart > 0) || + (iPrevLineContinues == 1)) { + + if (iStart == 0) { + /* Didn't match, so can only possibly be a continued line + Skip spaces, then process the rest of line as "normal" */ + for (iThisChar=0; iThisChar 0) ? 0 : 1; + iTarget--; + continue; + } + if (acLineIn[iThisChar] == '%') { + if (iQuoteCount == 1) { + /* Need to double up the number of %s */ + acLineOut[iTarget+iThisChar-iStart] = '%'; + iTarget++; + } + /* This also caters for where we're not in quotes, + so must just copy the % once */ + acLineOut[iTarget+iThisChar-iStart] = '%'; + continue; + } + if (acLineIn[iThisChar] == '>') { + if (acLineIn[iThisChar-1] == ' ') { + /* Need to remove any spaces between echo and redirection + as NT/2000/XP adds this to the output and mostly this is NOT wanted */ + iTarget--; + } + acLineOut[iTarget+iThisChar-iStart] = '>'; + continue; + } + if (strncmp("${TMPDIR}",acLineIn+iThisChar,9) == 0) { + strcpy(acLineOut+iTarget+iThisChar-iStart,"%TMPDIR%"); + /* %TMPDIR% is one char shorter than ${TMPDIR} */ + iTarget--; + /* skip forward to the end of the string matched + (less one as the loop will add one) */ + iThisChar += 8; + } else if (acLineIn[iThisChar] == '/') { + acLineOut[iTarget+iThisChar-iStart] = '\\'; + } else { + /* part of a literal, so copy the text */ + acLineOut[iTarget+iThisChar-iStart] = acLineIn[iThisChar]; + } + } /* for */ + if ((iEchoLevel == 1) && (iPrevLineContinues != 1)) { + f_outputLine(pfTestoOut, "@echo on"); + f_outputLine(pfTestoOut, "@echo Testing..."); + } + iPrevLineContinues = f_outputLine(pfTestoOut, acLineOut); + /* fputs("\r\n"); */ + } + else { + /* We didn't match the start of the line, so + - if blank, print it + */ + if (iEchoLevel > 0) { + f_outputLine(pfTestoOut, "@echo off"); + f_outputLine(pfTestoOut, "@echo."); + iEchoLevel = 0; + } + if ((acLineIn[0] == '\n') || + (acLineIn[0] == '\0') || + ((acLineIn[0] == '\r') && (acLineIn[1] == '\n') && (acLineIn[2] == '\0'))) { + iPrevLineContinues = f_outputLine(pfTestoOut, ""); + } + + } /* else... didn't match a start of line - so check rest of line */ + + } /* else ... catchall to mathing things on the start of the line */ + + } /* while */ + + /* We're done */ + fclose(pfTestoIn); + fclose(pfTestoOut); + } + } +} diff --git a/mingw/shapelib/.ignore b/mingw/shapelib/.ignore new file mode 100644 index 000000000..e69de29bb diff --git a/mingw/testo b/mingw/testo new file mode 100644 index 000000000..cce08aa19 --- /dev/null +++ b/mingw/testo @@ -0,0 +1,5 @@ +export PNAME="wine -- mingw/gpsbabel" + +cd .. +exec ./testo + diff --git a/mingw/wintesto.cmd b/mingw/wintesto.cmd new file mode 100644 index 000000000..e58576b30 --- /dev/null +++ b/mingw/wintesto.cmd @@ -0,0 +1,875 @@ +@echo off +REM +REM Simple Windows NT/2000/XP .cmd version of GPSBabel testo script +REM + +SET TMPDIR=%TEMP%\WINTESTO +MKDIR %TMPDIR% 2>NUL: + +GOTO :REALSTART + +REM ================================== + +:CommonCOMPARE +SET PARAM1=%2 +SET PARAM2=%3 +REM Test if param3 was a dir rather than a file, if so add a \* to make fc work +FOR %%A IN (%3) DO IF "d--------"=="%%~aA" SET PARAM2=%3\* +FOR /f "delims=" %%a IN ('fc %PARAM1% %PARAM2%') DO IF "x%%a"=="xFC: no differences encountered" GOTO :EOF +REM Show the first 5 lines of difference +fc %1 /LB5 %PARAM1% %PARAM2% +ECHO %* are not the same (first 5 differences above) - pausing. ^C to quit if required +PAUSE +GOTO :EOF + +REM ================================== + +:COMPARE +CALL :CommonCOMPARE /L %1 %2 +GOTO :EOF + +REM ================================== + +:BINCOMPARE +CALL :CommonCOMPARE /B %1 %2 +GOTO :EOF + +REM ================================== + +:SORTandCOMPARE +SORT <%1 >%TMPDIR%\s1 +SORT <%2 >%TMPDIR%\s2 +CALL :COMPARE %TMPDIR%\s1 %TMPDIR%\s2 +GOTO :EOF + +REM ================================== + +:REALSTART + + +SET PNAME=.\gpsbabel +IF NOT EXIST %PNAME% ECHO Can't find %PNAME%&& GOTO :EOF + + + + + + +REM Geocaching .loc +DEL %TMPDIR%\gl.loc +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o geo -F %TMPDIR%\gl.loc +@echo off +@echo. +CALL :COMPARE %TMPDIR%\gl.loc reference + +REM GPSUtil +DEL %TMPDIR%\gu.wpt %TMPDIR%\1.gpx %TMPDIR%\2.gpx +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o gpsutil -F %TMPDIR%\gu.wpt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\gu.wpt reference +@echo on +@echo Testing... +%PNAME% -i gpsutil -f %TMPDIR%\gu.wpt -o gpx -F %TMPDIR%\1.gpx +%PNAME% -i gpsutil -f reference\gu.wpt -o gpx -F %TMPDIR%\2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\1.gpx %TMPDIR%\2.gpx + +REM GPSman +DEL %TMPDIR%\gm.gm %TMPDIR%\gm.gm+ +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o gpsman -F %TMPDIR%\gm.gm +%PNAME% -i gpsman -f %TMPDIR%\gm.gm -o gpsutil -F %TMPDIR%\gm.gm+ +@echo off +@echo. +CALL :COMPARE %TMPDIR%\gm.gm+ %TMPDIR%\gu.wpt + +REM GPX +DEL %TMPDIR%\gl.gpx %TMPDIR%\gpx.gpx +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o gpx -F %TMPDIR%\gl.gpx +%PNAME% -i gpx -f %TMPDIR%\gl.gpx -o gpsutil -F %TMPDIR%\gpx.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\gpx.gpx %TMPDIR%\gu.wpt + +REM Magellan Mapsend +DEL %TMPDIR%\mm.mapsend %TMPDIR%\mm.gps +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o mapsend -F %TMPDIR%\mm.mapsend +%PNAME% -i mapsend -f %TMPDIR%\mm.mapsend -o gpsutil -F %TMPDIR%\mm.gps +@echo off +@echo. +CALL :COMPARE %TMPDIR%\mm.gps %TMPDIR%\gu.wpt + +REM Magellan serial +REM TODO + +REM Tiger +REM This one is a little tacky, becuase it's a very lossy format. +REM so we simply test we can write it, and then read it and write it and +REM get an identical file back. +DEL %TMPDIR%\tiger +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o tiger -F %TMPDIR%\tiger +%PNAME% -i tiger -f %TMPDIR%\tiger -o tiger -F %TMPDIR%\tiger2 +@echo off +@echo. +CALL :COMPARE %TMPDIR%\tiger %TMPDIR%\tiger2 + +REM CSV (Comma separated value) data. + +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o csv -F %TMPDIR%\csv.csv +%PNAME% -i csv -f %TMPDIR%\csv.csv -o csv -F %TMPDIR%\csv2.csv +@echo off +@echo. +CALL :COMPARE %TMPDIR%\csv2.csv %TMPDIR%\csv.csv + +REM +REM Delorme TopoUSA 4 is a CSV strain. +REM +DEL %TMPDIR%\xmap-1.gpx %TMPDIR%\xmap-2.gpx %TMPDIR%\xmap +@echo on +@echo Testing... +%PNAME% -i xmap -f reference\xmap -o xmap -F %TMPDIR%\xmap +%PNAME% -i xmap -f reference\xmap -o gpx -F %TMPDIR%\xmap-1.gpx +%PNAME% -i xmap -f %TMPDIR%\xmap -o gpx -F %TMPDIR%\xmap-2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\xmap-1.gpx %TMPDIR%\xmap-2.gpx +CALL :COMPARE reference\xmap %TMPDIR%\xmap + +REM PCX (Garmin mapsource import) file format +DEL %TMPDIR%\mm.pcx %TMPDIR%\pcx.gps +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o pcx -F %TMPDIR%\mm.pcx +%PNAME% -i pcx -f %TMPDIR%\mm.pcx -o gpsutil -F %TMPDIR%\pcx.gps +@echo off +@echo. +CALL :COMPARE %TMPDIR%\mm.gps %TMPDIR%\gu.wpt + +REM Magellan file format +@echo on +@echo Testing... +%PNAME% -i magellan -f reference\magfile -o magellan -F %TMPDIR%\magfile +@echo off +@echo. +CALL :COMPARE %TMPDIR%\magfile reference\magfile + +REM Navitrak DNA marker format +@echo on +@echo Testing... +%PNAME% -i dna -f reference\dnatest.txt -o dna -F %TMPDIR%\dnatest.txt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\dnatest.txt reference\dnatest.txt + +REM PSP (PocketStreets 2002 Pushpin (.PSP)) file format. Use mxf as an +REM intermediate format to avoid binary FP anomalies on compareerent platforms. +DEL %TMPDIR%\psp.mxf %TMPDIR%\mxf.psp +@echo on +@echo Testing... +%PNAME% -i psp -f reference\ps.psp -o mxf -F %TMPDIR%\psp.mxf +%PNAME% -i geo -f geocaching.loc -o mxf -F %TMPDIR%\mxf.psp +@echo off +@echo. +CALL :COMPARE %TMPDIR%\psp.mxf %TMPDIR%\mxf.psp +@echo on +@echo Testing... +%PNAME% -i psp -f reference\ps.psp -o gpx -F %TMPDIR%\psp1.gpx +%PNAME% -i psp -f reference\ps.psp -o psp -F %TMPDIR%\xxx.psp +%PNAME% -i psp -f %TMPDIR%\xxx.psp -o gpx -F %TMPDIR%\psp2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\psp1.gpx %TMPDIR%\psp2.gpx + +REM MXF (Maptech Exchange Format) file format +DEL %TMPDIR%\mx.mxf %TMPDIR%\mxf.mxf +@echo on +@echo Testing... +%PNAME% -i mxf -f reference\mxf.mxf -o mxf -F %TMPDIR%\mx.mxf +%PNAME% -i mxf -f %TMPDIR%\mx.mxf -o mxf -F %TMPDIR%\mxf.mxf +@echo off +@echo. +CALL :COMPARE %TMPDIR%\mxf.mxf reference + +REM tmpro (TopoMapPro Places) file format +DEL %TMPDIR%\topomappro.txt %TMPDIR%\mxf.mxf +@echo on +@echo Testing... +%PNAME% -i tmpro -f reference\topomappro.txt -o tmpro -F %TMPDIR%\tmp.txt +%PNAME% -i tmpro -f %TMPDIR%\tmp.txt -o tmpro -F %TMPDIR%\topomappro.txt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\topomappro.txt reference + +REM TPG (NG Topo!) file format +REM This is hard to test as the datum conversions create minute +REM inconsistencies in the coordinates. So.. we test our i/o +REM against a format that rounds higher than we care to compare +REM for binary data. +DEL %TMPDIR%\topo.mxf %TMPDIR%\tpg.mxf %TMPDIR%\geo.tpg +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o tpg -F %TMPDIR%\geo.tpg +%PNAME% -i tpg -f %TMPDIR%\geo.tpg -o mxf -F %TMPDIR%\tpg.mxf +%PNAME% -i tpg -f reference\tpg.tpg -o mxf -F %TMPDIR%\topo.mxf +@echo off +@echo. +CALL :COMPARE %TMPDIR%\tpg.mxf %TMPDIR%\topo.mxf + +REM OZI (OziExplorer 1.1) file format +DEL %TMPDIR%\oz.wpt %TMPDIR%\ozi.wpt +@echo on +@echo Testing... +%PNAME% -i ozi -f reference\ozi.wpt -o ozi -F %TMPDIR%\oz.wpt +%PNAME% -i ozi -f %TMPDIR%\oz.wpt -o ozi -F %TMPDIR%\ozi.wpt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\ozi.wpt reference + +REM Holux support is a little funky to test. Becuase it loses precision, +REM if we convert it to another format, we lose accuracy (rounding) in the +REM coords, so converting it so something else and comparing it never works. +REM So we verify that we can read the reference and write it and get an +REM identical reference. +@echo on +@echo Testing... +%PNAME% -i holux -f reference\paris.wpo -o holux -F %TMPDIR%\paris.wpo +@echo off +@echo. +CALL :COMPARE reference\paris.wpo %TMPDIR%\paris.wpo + +REM Magellan NAV Companion for PalmOS +REM This format is hard to test, because each record and the database itself +REM contains the time of creation, so two otherwise identical files won't +REM compare accurately. In any case, the files are binary so compare wouldn't +REM like them. So, we convert the reference file to gpsutil and the converted +REM file to gpsutil and make sure they're the same, and that they're the same +REM as one converted on a known-working installation. Unfortunately, this does +REM not verify that the appinfo block was written correctly. However, it does +REM successfully test for some endianness errors that might otherwise go +REM unnoticed. +DEL %TMPDIR%\magnav.pdb %TMPDIR%\magnav.gpu %TMPDIR%\magnavt.gpu +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o magnav -F %TMPDIR%\magnav.pdb +%PNAME% -i magnav -f %TMPDIR%\magnav.pdb -o gpsutil -F %TMPDIR%\magnav.gpu +%PNAME% -i magnav -f reference\magnav.pdb -o gpsutil -F %TMPDIR%\magnavt.gpu +@echo off +@echo. +CALL :COMPARE %TMPDIR%\magnavt.gpu %TMPDIR%\magnav.gpu +CALL :COMPARE reference\gu.wpt %TMPDIR%\magnav.gpu + +DEL %TMPDIR%\magnav.pdb +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o magnav -F %TMPDIR%\magnav.pdb +@echo off +@echo. +CALL :BINCOMPARE %TMPDIR%\magnav.pdb reference\magnav.pdb + + + +REM GPSPilot Tracker for PalmOS +REM This test is eerily similar to the NAV Companion test. In fact, the +REM converted reference file (magnavr.gpu) is identical. +DEL %TMPDIR%\gpspilot.pdb %TMPDIR%\gpspilot.gpu %TMPDIR%\gpspil_t.gpu +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o gpspilot -F %TMPDIR%\gpspilot.pdb +%PNAME% -i gpspilot -f %TMPDIR%\gpspilot.pdb -o gpsutil -F %TMPDIR%\gpspilot.gpu +%PNAME% -i gpspilot -f reference\gpspilot.pdb -o gpsutil -F %TMPDIR%\gpspil_t.gpu +@echo off +@echo. +CALL :COMPARE %TMPDIR%\gpspil_t.gpu %TMPDIR%\gpspilot.gpu +CALL :COMPARE reference\gu.wpt %TMPDIR%\gpspilot.gpu + +REM Cetus GPS for PalmOS +REM This test is also similar to the NAV Companion test. +DEL %TMPDIR%\cetus.pdb %TMPDIR%\cetus.gpu %TMPDIR%\cetust.gpu +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o cetus -F %TMPDIR%\cetus.pdb +%PNAME% -i cetus -f %TMPDIR%\cetus.pdb -o gpsutil -F %TMPDIR%\cetus.gpu +%PNAME% -i cetus -f reference\cetus.pdb -o gpsutil -F %TMPDIR%\cetust.gpu +@echo off +@echo. +CALL :COMPARE %TMPDIR%\cetust.gpu %TMPDIR%\cetus.gpu +CALL :COMPARE reference\cetus.gpu %TMPDIR%\cetus.gpu + +REM QuoVadis GPS for PalmOS +REM This test is derived from the Cetus test above. +DEL %TMPDIR%\quovadis.pdb %TMPDIR%\quovadis.gpu %TMPDIR%\quovadist.gpu +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o quovadis -F %TMPDIR%\quovadis.pdb +%PNAME% -i quovadis -f %TMPDIR%\quovadis.pdb -o gpsutil -F %TMPDIR%\quovadis.gpu +%PNAME% -i quovadis -f reference\quovadis.pdb -o gpsutil -F %TMPDIR%\quovadist.gpu +@echo off +@echo. +CALL :COMPARE %TMPDIR%\quovadist.gpu %TMPDIR%\quovadis.gpu +CALL :COMPARE reference\quovadis.gpu %TMPDIR%\quovadis.gpu + +REM GpsDrive +DEL %TMPDIR%\gpsdrive.txt +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o gpsdrive -F %TMPDIR%\gpsdrive.txt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\gpsdrive.txt reference +@echo on +@echo Testing... +%PNAME% -i gpsdrive -f reference\gpsdrive.txt -o gpsdrive -F %TMPDIR%\gpsdrive2.txt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\gpsdrive2.txt reference\gpsdrive.txt + +REM XMapHH Street Atlas USA file format +DEL %TMPDIR%\xmapwpt.wpt %TMPDIR%\xmapwpt.xmapwpt +@echo on +@echo Testing... +%PNAME% -i xmapwpt -f reference\xmapwpt.wpt -o xmapwpt -F %TMPDIR%\xmapwpt.xmapwpt +%PNAME% -i xmapwpt -f %TMPDIR%\xmapwpt.xmapwpt -o xmapwpt -F %TMPDIR%\xmapwpt.wpt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\xmapwpt.wpt reference + +REM XCSV +REM Test that we can parse a style file, and read and write data in the +REM same xcsv format (a complete test is virtually impossible). +ECHO RECORD_DELIMITER NEWLINE> %TMPDIR%\testo.style +ECHO FIELD_DELIMITER COMMA>> %TMPDIR%\testo.style +ECHO BADCHARS COMMA>> %TMPDIR%\testo.style +ECHO PROLOGUE Header>> %TMPDIR%\testo.style +ECHO EPILOGUE Footer>> %TMPDIR%\testo.style +ECHO IFIELD SHORTNAME,,%%s>> %TMPDIR%\testo.style +ECHO IFIELD LAT_DIRDECIMAL,,%%c%%lf>> %TMPDIR%\testo.style +ECHO IFIELD LON_DECIMALDIR,,%%lf%%c>> %TMPDIR%\testo.style +DEL %TMPDIR%\xcsv.geo %TMPDIR%\xcsv.xcsv +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o xcsv,style=%TMPDIR%\testo.style -F %TMPDIR%\xcsv.geo +%PNAME% -i xcsv,style=%TMPDIR%\testo.style -f %TMPDIR%\xcsv.geo -o xcsv,style=%TMPDIR%\testo.style -F %TMPDIR%\xcsv.xcsv +@echo off +@echo. +CALL :COMPARE %TMPDIR%\xcsv.geo %TMPDIR%\xcsv.xcsv + +REM Garmin Mapsource This is a binary format with some undocumented +REM fields. This test is therefore intentionally vague. We read a file, +REM convert it to GPX, then write a file as MPS, then read it back and +REM write it as GPX and compare them. Since we're writing both GPX files +REM ourselves from the same version, we're immune to changes in our own +REM GPX output. + +@echo on +@echo Testing... +%PNAME% -i mapsource -f reference\mapsource.mps -o gpx -F %TMPDIR%\ms1.gpx +%PNAME% -i mapsource -f reference\mapsource.mps -o mapsource -F %TMPDIR%\ms.mps +%PNAME% -i mapsource -f %TMPDIR%\ms.mps -o gpx -F %TMPDIR%\ms2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\ms1.gpx %TMPDIR%\ms2.gpx + +REM +REM MRCB mapsource track test +REM +DEL %TMPDIR%\mps-track.mps +@echo on +@echo Testing... +%PNAME% -t -i mapsource -f reference\track\mps-track.mps -o mapsource,mpsverout=3 -F %TMPDIR%\mps-track.mps +@echo off +@echo. +CALL :COMPARE %TMPDIR%\mps-track.mps reference\track +REM Now do a test of reading waypoints from a track-only file - should have an empty result +DEL %TMPDIR%\mps-track.mps +@echo on +@echo Testing... +%PNAME% -i mapsource -f reference\track\mps-track.mps -o mapsource,mpsverout=3 -F %TMPDIR%\mps-track.mps +@echo off +@echo. +CALL :COMPARE %TMPDIR%\mps-track.mps reference\mps-empty.mps + +REM +REM MRCB mapsource route test +REM +DEL %TMPDIR%\mps-route.mps +@echo on +@echo Testing... +%PNAME% -r -i mapsource -f reference\route\route.mps -o mapsource,mpsverout=4 -F %TMPDIR%\mps-route.mps +@echo off +@echo. +CALL :COMPARE %TMPDIR%\mps-route.mps reference\route\route.mps + +REM Now do a test of reading tracks from a route-only file - should have an empty result +DEL %TMPDIR%\mps-route.mps +@echo on +@echo Testing... +%PNAME% -t -i mapsource -f reference\route\route.mps -o mapsource,mpsverout=3 -F %TMPDIR%\mps-route.mps +@echo off +@echo. +CALL :COMPARE %TMPDIR%\mps-route.mps reference\mps-empty.mps + +REM +REM Geocaching Database is a binary Palm format that, like the GPX variants +REM has a zillion "equivalent" encodings of any given record set. So we +REM read the reference file, spin it to GPX and back to GCDB and then spin +REM that one to GPX. +REM + +@echo on +@echo Testing... +%PNAME% -i gcdb -f reference\GeocachingDB.PDB -o gpx -F %TMPDIR%\gcdb1.gpx -o gcdb -F %TMPDIR%\gcdb1.pdb +%PNAME% -i gpx -f %TMPDIR%\gcdb1.gpx -o gpx -F %TMPDIR%\gcdb2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\gcdb1.gpx %TMPDIR%\gcdb1.gpx + +REM +REM Duplicate filter - Since filters have no format of their own, we use csv +REM as an intermediate format for testing the filter. +REM +DEL %TMPDIR%\filterdupe.csv1 %TMPDIR%\filterdupe.csv2 +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o csv -F %TMPDIR%\filterdupe.csv1 +%PNAME% -i geo -f geocaching.loc -f geocaching.loc -x duplicate,shortname -o csv -F %TMPDIR%\filterdupe.csv2 +@echo off +@echo. +CALL :SORTandCOMPARE %TMPDIR%\filterdupe.csv1 %TMPDIR%\filterdupe.csv2 + +REM +REM Position filter - Since very small distances are essentialy a duplicate +REM position filter, we can test very similarly to the duplicate filter. +REM +DEL %TMPDIR%\filterpos.csv1 %TMPDIR%\filterpos.csv2 +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o csv -F %TMPDIR%\filterpos.csv1 +%PNAME% -i geo -f geocaching.loc -f geocaching.loc -x position,distance=5f -o csv -F %TMPDIR%\filterpos.csv2 +@echo off +@echo. +CALL :SORTandCOMPARE %TMPDIR%\filterpos.csv1 %TMPDIR%\filterpos.csv2 + +REM +REM Radius filter +REM +DEL %TMPDIR%\radius.csv +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -x radius,lat=35.9720,lon=-87.1347,distance=14.7 -o csv -F %TMPDIR%\radius.csv +@echo off +@echo. +CALL :COMPARE %TMPDIR%\radius.csv reference +REM +REM magellan SD card waypoint / route format +REM +DEL %TMPDIR%\magellan.rte +@echo on +@echo Testing... +%PNAME% -r -i magellan -f reference\route\magellan.rte -o magellan -F %TMPDIR%\magellan.rte +@echo off +@echo. +CALL :COMPARE %TMPDIR%\magellan.rte reference\route\magellan.rte + +REM +REM GPX routes -- since GPX contains a date stamp, tests will always +REM fail, so we use magellan as an interim format... +REM +DEL %TMPDIR%\gpxroute.gpx %TMPDIR%\maggpx.rte +@echo on +@echo Testing... +%PNAME% -r -i gpx -f reference\route\route.gpx -o gpx -F %TMPDIR%\gpxroute.gpx +%PNAME% -r -i gpx -f %TMPDIR%\gpxroute.gpx -o magellan -F %TMPDIR%\maggpx.rte +@echo off +@echo. +CALL :COMPARE %TMPDIR%\maggpx.rte reference\route\magellan.rte + +REM +REM GPX tracks -- since GPX contains a date stamp, tests will always +REM fail, so we use magellan as an interim format... +REM +DEL %TMPDIR%\gpxtrack.gpx %TMPDIR%\maggpx.trk +@echo on +@echo Testing... +%PNAME% -t -i gpx -f reference\track\tracks.gpx -o gpx -F %TMPDIR%\gpxtrack.gpx +%PNAME% -t -i magellan -f reference\track\meridian.trk -o gpx -F %TMPDIR%\maggpx.trk +@echo off +@echo. +CALL :COMPARE %TMPDIR%\maggpx.trk %TMPDIR%\gpxtrack.gpx + +REM +REM MAPSEND waypoint / route format +REM +DEL %TMPDIR%\route.mapsend +@echo on +@echo Testing... +%PNAME% -r -i mapsend -f reference\route\route.mapsend -o mapsend -F %TMPDIR%\route.mapsend +@echo off +@echo. +CALL :COMPARE %TMPDIR%\route.mapsend reference\route +REM +REM MAPSEND track format +REM +DEL %TMPDIR%\mapsend.trk +@echo on +@echo Testing... +%PNAME% -t -i mapsend -f reference\track\mapsend.trk -o mapsend -F %TMPDIR%\mapsend.trk +@echo off +@echo. +CALL :COMPARE %TMPDIR%\mapsend.trk reference\track +REM +REM copilot +REM +DEL %TMPDIR%\copilot.pdb +@echo on +@echo Testing... +%PNAME% -i copilot -f reference\UKultralight.pdb -o copilot -F %TMPDIR%\cop.pdb +%PNAME% -i copilot -f reference\UKultralight.pdb -o gpx -F %TMPDIR%\cop1.gpx +%PNAME% -i copilot -f %TMPDIR%\cop.pdb -o gpx -F %TMPDIR%\cop2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\cop1.gpx %TMPDIR%\cop2.gpx + +REM +REM EasyGPS. Another binary format. +REM +DEL %TMPDIR%\easy.loc +@echo on +@echo Testing... +%PNAME% -i easygps -f reference\easygps.loc -o easygps -F %TMPDIR%\ez.loc +%PNAME% -i easygps -f reference\easygps.loc -o gpx -F %TMPDIR%\ez1.gpx +%PNAME% -i easygps -f %TMPDIR%\ez.loc -o gpx -F %TMPDIR%\ez2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\ez1.gpx %TMPDIR%\ez2.gpx + +REM +REM GPilotS. A Palm format. Another binary format that +REM +REM rm -f ${TMPDIR/gpilots.l +REM ${PNAME} -i easygps -f reference/gpilots.pdb -o gpx -F ${TMPDIR}/gp.gpx +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o gpilots -F %TMPDIR%\blah.pdb +%PNAME% -i gpilots -f %TMPDIR%\blah.pdb -o gpx -F %TMPDIR%\1.gpx +%PNAME% -i gpilots -f reference\gpilots.pdb -o gpx -F %TMPDIR%\2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\1.gpx %TMPDIR%\2.gpx +REM ${PNAME} -i easygps -f reference/gpilots.pdb -o gpx -F ${TMPDIR}/gp.gpx + +REM +REM Navicache. +@echo on +@echo Testing... +%PNAME% -i navicache -f reference\navicache.xml -o gpsutil -F %TMPDIR%\navi.wpt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\navi.wpt reference\navicache.ref +REM + +REM PsiTrex. A text format that can't be handled by XCSV due to context of +REM data based on other data values in the file +REM Waypoints first +DEL %TMPDIR%\psit-ww.txt %TMPDIR%\psit-ww.mps +@echo on +@echo Testing... +%PNAME% -i psitrex -f reference\psitwpts.txt -o mapsource -F %TMPDIR%\psit-ww.mps +%PNAME% -i mapsource -f %TMPDIR%\psit-ww.mps -o psitrex -F %TMPDIR%\psit-ww.txt +@echo off +@echo. +CALL :COMPARE reference\psitwpts.txt %TMPDIR%\psit-ww.txt + +REM Now test correct "empty" handling - ask for routes when there aren't any +REM Uses mapsource as the empty handling for this has already happened above +DEL %TMPDIR%\psit-wr.mps +@echo on +@echo Testing... +%PNAME% -r -i psitrex -f reference\psitwpts.txt -o mapsource,mpsverout=3 -F %TMPDIR%\psit-wr.mps +@echo off +@echo. +CALL :COMPARE reference\mps-empty.mps %TMPDIR%\psit-wr.mps + +REM Routes next +DEL %TMPDIR%\psit-rr.txt %TMPDIR%\psit-rr.mps +@echo on +@echo Testing... +%PNAME% -r -i psitrex -f reference\route\psitrtes.txt -o mapsource -F %TMPDIR%\psit-rr.mps +%PNAME% -r -i mapsource -f %TMPDIR%\psit-rr.mps -o psitrex -F %TMPDIR%\psit-rr.txt +@echo off +@echo. +CALL :COMPARE reference\route\psitrtes.txt %TMPDIR%\psit-rr.txt + +REM Now test correct "empty" handling - ask for tracks when there aren't any +REM Uses mapsource as the empty handling for this has already happened above +DEL %TMPDIR%\psit-rt.mps +@echo on +@echo Testing... +%PNAME% -t -i psitrex -f reference\route\psitrtes.txt -o mapsource,mpsverout=3 -F %TMPDIR%\psit-rt.mps +@echo off +@echo. +CALL :COMPARE reference\mps-empty.mps %TMPDIR%\psit-rt.mps + +REM Tracks last +DEL %TMPDIR%\psit-tt.txt %TMPDIR%\psit-tt.mps +@echo on +@echo Testing... +%PNAME% -t -i psitrex -f reference\track\psittrks.txt -o mapsource -F %TMPDIR%\psit-tt.mps +%PNAME% -t -i mapsource -f %TMPDIR%\psit-tt.mps -o psitrex -F %TMPDIR%\psit-tt.txt +@echo off +@echo. +CALL :COMPARE reference\track\psittrks.txt %TMPDIR%\psit-tt.txt + +REM Now test correct "empty" handling - ask for waypoints when there aren't any +REM Uses mapsource as the empty handling for this has already happened above +DEL %TMPDIR%\psit-tw.mps +@echo on +@echo Testing... +%PNAME% -i psitrex -f reference\track\psittrks.txt -o mapsource,mpsverout=3 -F %TMPDIR%\psit-tw.mps +@echo off +@echo. +CALL :COMPARE reference\mps-empty.mps %TMPDIR%\psit-tw.mps + +REM +REM Arc Distance filter +REM +DEL %TMPDIR%\arcdist.txt +@echo on +@echo Testing... +%PNAME% -i xmap -f reference\arcdist_input.txt -x arc,file=reference\arcdist_arc.txt,distance=1 -o xmap -F %TMPDIR%\arcdist.txt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\arcdist.txt reference\arcdist_output.txt + +REM +REM Polygon filter +REM +DEL %TMPDIR%\polygon.txt +@echo on +@echo Testing... +%PNAME% -i xmap -f reference\arcdist_input.txt -x polygon,file=reference\polygon_allencty.txt -o xmap -F %TMPDIR%\polygon.txt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\polygon.txt reference\polygon_output.txt + +REM +REM Simplify filter +REM +DEL %TMPDIR%\simplify.txt +@echo on +@echo Testing... +%PNAME% -r -i gpx -f reference\route\route.gpx -x simplify,count=10 -o arc -F %TMPDIR%\simplify.txt +@echo off +@echo. +CALL :COMPARE %TMPDIR%\simplify.txt reference\simplify_output.txt + +REM +REM Route reversal filter. Do it twice and be sure we get what we +REM started with. +REM +DEL %TMPDIR%\reverse1.arc %TMPDIR%\reverse2.arc %TMPDIR%\reference.arc +@echo on +@echo Testing... +%PNAME% -r -i gpx -f reference\route\route.gpx -o arc -F %TMPDIR%\reference.arc +%PNAME% -r -i gpx -f reference\route\route.gpx -x reverse -o arc -F %TMPDIR%\reverse1.arc +%PNAME% -r -i gpx -f reference\route\route.gpx -x reverse -x reverse -o arc -F %TMPDIR%\reverse2.arc +@echo off +@echo. +REM Verify the first and last are the same +CALL :COMPARE %TMPDIR%\reference.arc %TMPDIR%\reverse2.arc +REM Verify the first and second are different. +REM ${DIFF} ${TMPDIR}/reverse1.arc ${TMPDIR}/reverse2.arc > /dev/null && { +REM echo ERROR Failed reversal test. +REM exit 1 +REM } + +REM parkrrrr: This isn't a straightforward compare; we *want* it to fail. +REM Obviously this test should just be rewritten with a new reference. +REM compare ${TMPDIR}/reverse1.arc ${TMPDIR}/reverse2.arc + +REM +REM Geoniche: No reference file was available, so we created one and just +REM test it against itself. +REM +DEL %TMPDIR%\gn.pdb %TMPDIR%\1.gpx %TMPDIR%\2.gpx +@echo on +@echo Testing... +%PNAME% -i geoniche -f reference\geoniche.pdb -o geoniche -F %TMPDIR%\gn.pdb +%PNAME% -i geoniche -f reference\geoniche.pdb -o gpx -F %TMPDIR%\1.gpx +%PNAME% -i geoniche -f %TMPDIR%\gn.pdb -o gpx -F %TMPDIR%\2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\1.gpx %TMPDIR%\2.gpx + +REM +REM saroute covers *.anr, *.rte, and *.rtd, but I only have an .anr for testing. +REM Unfortunately for us, this is a read-only format for now. +REM +@echo on +@echo Testing... +%PNAME% -t -i saroute -f reference\track\i65.anr -o gpx -F %TMPDIR%\gpl1.gpx +%PNAME% -t -i gpx -f reference\track\i65.anr.gpx -o gpx -F %TMPDIR%\gpl2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\gpl1.gpx %TMPDIR%\gpl2.gpx + +REM +REM Delorme GPL file. This is sort of a track format. +REM +DEL %TMPDIR%\gpl1.gpx %TMPDIR%\gpl2.gpx %TMPDIR%\gpl1.gpl +@echo on +@echo Testing... +%PNAME% -t -i gpl -f reference\track\webpark1.gpl -o gpx -F %TMPDIR%\gpl1.gpx +%PNAME% -t -i gpl -f reference\track\webpark1.gpl -o gpl -F %TMPDIR%\gpl1.gpl +%PNAME% -t -i gpl -f %TMPDIR%\gpl1.gpl -o gpx -F %TMPDIR%\gpl2.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\gpl1.gpx %TMPDIR%\gpl2.gpx + +REM +REM NetStumbler Summary File (read-only) +REM +DEL %TMPDIR%\netstumbler.mps +@echo on +@echo Testing... +%PNAME% -i netstumbler -f reference\netstumbler.txt -o mapsource -F %TMPDIR%\netstumbler.mps +@echo off +@echo. +CALL :BINCOMPARE %TMPDIR%\netstumbler.mps reference\netstumbler.mps + +REM +REM IGC tests +REM +DEL %TMPDIR%\igc*out +@echo on +@echo Testing... +%PNAME% -i gpx -f reference\igc1.gpx -o igc -F %TMPDIR%\igc.out +@echo off +@echo. +FINDSTR /V "XXXGenerated by GPSBabel Version" %TMPDIR%\igc.out> %TMPDIR%\igc_sed.out +CALL :COMPARE %TMPDIR%\igc_sed.out reference\igc1_igc.out + +@echo on +@echo Testing... +%PNAME% -i igc -f %TMPDIR%\igc.out -o gpx -F %TMPDIR%\igc.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\igc.gpx reference\igc1_gpx.out + +@echo on +@echo Testing... +%PNAME% -i gpx -f %TMPDIR%\igc.gpx -o igc -F %TMPDIR%\igc.out +@echo off +@echo. +FINDSTR /V "XXXGenerated by GPSBabel Version" %TMPDIR%\igc.out> %TMPDIR%\igc_sed.out +CALL :COMPARE %TMPDIR%\igc_sed.out reference\igc1_igc.out + +@echo on +@echo Testing... +%PNAME% -i gpx -f reference\igc1_baro.gpx -i igc -f reference\igc1_igc.out -o igc,timeadj=auto -F %TMPDIR%\igc.out +@echo off +@echo. +FINDSTR /V "XXXGenerated by GPSBabel Version" %TMPDIR%\igc.out> %TMPDIR%\igc_sed.out +CALL :COMPARE %TMPDIR%\igc_sed.out reference\igc1_3d.out + + +@echo on +@echo Testing... +%PNAME% -i igc -f reference\igc2.igc -o gpx -F %TMPDIR%\igc.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\igc.gpx reference\igc2_gpx.out + +@echo on +@echo Testing... +%PNAME% -i gpx -f %TMPDIR%\igc.gpx -o igc -F %TMPDIR%\igc.out +@echo off +@echo. +FINDSTR /V "XXXGenerated by GPSBabel Version" %TMPDIR%\igc.out> %TMPDIR%\igc_sed.out +CALL :COMPARE %TMPDIR%\igc_sed.out reference\igc2_igc.out + +@echo on +@echo Testing... +%PNAME% -i igc -f %TMPDIR%\igc.out -o gpx -F %TMPDIR%\igc.gpx +@echo off +@echo. +CALL :COMPARE %TMPDIR%\igc.gpx reference\igc2_gpx.out + + +REM +REM XCSV "human readable" tests +REM +DEL %TMPDIR%\humanread.out +@echo on +@echo Testing... +%PNAME% -i xcsv,style=reference\humanread.style -f reference\human.in -o arc -F %TMPDIR%\humanread.out +@echo off +@echo. +CALL :COMPARE %TMPDIR%\humanread.out reference\humanread.out + +DEL %TMPDIR%\humanwrite.out +@echo on +@echo Testing... +%PNAME% -i xcsv,style=reference\humanread.style -f reference\human.in -o xcsv,style=reference\humanwrite.style -F %TMPDIR%\humanwrite.out +@echo off +@echo. +CALL :COMPARE %TMPDIR%\humanwrite.out reference\humanwrite.out + +REM +REM XCSV "path distance" test +REM +DEL %TMPDIR%\pathdist.out +@echo on +@echo Testing... +%PNAME% -i magellan -f reference\dusky.trk -o xcsv,style=reference\gnuplot.style -F %TMPDIR%\pathdist.out +@echo off +@echo. +CALL :COMPARE %TMPDIR%\pathdist.out reference\dusky.gnuplot + +REM hsandv +DEL %TMPDIR%\hsandv.exp %TMPDIR%\1.exp %TMPDIR%\1.exp %TMPDIR%\Glad_5.exp +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -o hsandv -F %TMPDIR%\hsandv.exp +@echo off +@echo. +CALL :COMPARE %TMPDIR%\hsandv.exp reference +REM the hsandv format is too lossy to do this test :( +REM ${PNAME} -i hsandv -f ${TMPDIR}/hsandv.exp -o geo -F ${TMPDIR}/1.exp +REM ${PNAME} -i hsandv -f reference/hsandv.exp -o geo -F ${TMPDIR}/2.exp +REM compare ${TMPDIR}/1.exp ${TMPDIR}/2.exp +REM test conversion from v4 to v5 files +@echo on +@echo Testing... +%PNAME% -i hsandv -f reference\Glad_4.exp -o hsandv -F %TMPDIR%\Glad_5.exp +@echo off +@echo. +REM FIXME: Can't compare directly because of potential FP rounding. +REM FIXME: compare ${TMPDIR}/Glad_5.exp reference + +REM +REM stack filter tests +REM These don't actually test for proper behavior, for now, but they do +REM exercise all of the currently-extant filter code. +REM + +@echo on +@echo Testing... +%PNAME% -i geo -f geocaching.loc -x stack,push,copy,nowarn -x stack,push,copy -x stack,push -x stack,pop,replace -x stack,pop,append -x stack,push,copy -x stack,pop,discard -x stack,swap,depth=1 -o +@echo off +@echo. + diff --git a/mkshort.c b/mkshort.c new file mode 100644 index 000000000..15d69bcea --- /dev/null +++ b/mkshort.c @@ -0,0 +1,550 @@ +/* + Generate unique short names. + + Copyright (C) 2003, 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include +#include + +#include "defs.h" + +static const char vowels[] = "aeiouAEIOU"; + +#define DEFAULT_TARGET_LEN 8 +#define DEFAULT_BADCHARS "\"$.,'!-" + +/* + * Hash table tunings. The reality is that our hash doesn't have to be + * terribly complex; our strings are short (typically 8-20 bytes) and the + * string hash mixes things up enough that strcmp can generally bail on the + * first byte or two for a mismatch. + */ +#define PRIME 37 + +typedef struct { + int mustupper; + int whitespaceok; + unsigned int target_len; + char *badchars; + int must_uniq; + queue namelist[PRIME]; + int depth[PRIME]; +} mkshort_handle; + +typedef struct { + queue list; + char *orig_shortname; + int conflictctr; +} uniq_shortname; + +/* + * We hash all strings as upper case. + */ +unsigned int hash_string(const char *key) +{ + unsigned int hash = 0; + while (*key) { + hash = ((hash<<5) ^ (hash>>27)) ^ toupper(*key++); + } + hash = hash % PRIME; + return hash; +} + +void * +#ifdef DEBUG_MEM +MKSHORT_NEW_HANDLE(DEBUG_PARAMS) +#else +mkshort_new_handle() +#endif +{ + int i; + mkshort_handle *h = xxcalloc(sizeof *h, 1, file, line); + + for (i = 0; i < PRIME; i++) + QUEUE_INIT(&h->namelist[i]); + + h->whitespaceok = 1; + h->badchars = DEFAULT_BADCHARS; + h->target_len = DEFAULT_TARGET_LEN; + h->must_uniq=1; + + return h; +} + +static +int +is_unique(mkshort_handle *h, char *name) +{ + queue *e, *t; + int hash; + + hash = hash_string(name); + QUEUE_FOR_EACH(&h->namelist[hash], e, t) { + uniq_shortname *z = (uniq_shortname *) e; + if (0 == case_ignore_strcmp(z->orig_shortname, name)) { + return 0; + } + } + return 1; +} + +static +void +add_to_hashlist(mkshort_handle *h, char *name) +{ + int hash = hash_string(name); + uniq_shortname *s = xcalloc(1, sizeof (uniq_shortname)); + + s->orig_shortname = xstrdup(name); + ENQUEUE_TAIL(&h->namelist[hash], &s->list); +} + +char * +mkshort_add_to_list(mkshort_handle *h, char *name) +{ + while (!is_unique(h, name)) { + int dl; + char tbuf[10]; + size_t l = strlen(name); + int hash = hash_string(name); + uniq_shortname *s = (uniq_shortname *) h->namelist[hash].next; + + s->conflictctr++; + + dl = sprintf(tbuf, ".%d", s->conflictctr); + + if (l + dl < h->target_len) { + name = xrealloc(name, l + dl + 1); + strcat(name, tbuf); + } + else { + strcpy(&name[l-dl], tbuf); + } + } + + add_to_hashlist(h, name); + return name; +} + +void +mkshort_del_handle(void *h) +{ + mkshort_handle *hdr = h; + int i; + + if (hdr) { + for (i = 0; i < PRIME; i++) { + queue *e, *t; + QUEUE_FOR_EACH(&hdr->namelist[i], e, t) { + uniq_shortname *s = (uniq_shortname *) e; + dequeue(e); + xfree(s->orig_shortname); + xfree(s); + } + } + xfree(hdr); + } +} + +/* + * This is the stuff that makes me ashamed to be a C programmer... + */ + +static +char * +delete_last_vowel(int start, char *istring, int *replaced) +{ + int l; + + /* + * Basically impelement strrchr. + */ + *replaced = 0; + for (l = strlen(istring); l > start; l--) { + if (strchr(vowels, istring[l-1])) { + char *ostring = xstrdup(istring); + + strncpy(&ostring[l-1], &istring[l], 1+strlen(istring)-l); + ostring[strlen(istring)-1] = 0; + *replaced = 1; + strcpy( istring, ostring ); + xfree(ostring); + break; + } + } + return istring; + +} + +/* + * Externally callable function to set the max length of the + * strings returned by mkshort(). 0 resets to default. + */ +void +setshort_length(void *h, int l) +{ + mkshort_handle *hdl = h; + if (l == 0) { + hdl->target_len = DEFAULT_TARGET_LEN; + } else { + hdl->target_len = l; + } +} + +void +setshort_whitespace_ok(void *h, int l) +{ + mkshort_handle *hdl = h; + hdl->whitespaceok = l; +} + +/* + * Externally callable function to set the string of characters + * that must never appear in a string returned by mkshort. NULL + * resets to default. + */ +void +setshort_badchars(void *h, const char *s) +{ + mkshort_handle *hdl = h; + if (s == NULL) { + hdl->badchars = DEFAULT_BADCHARS; + } else { + hdl->badchars = xstrdup(s); + } +} + +void +setshort_mustupper(void *h, int i) +{ + mkshort_handle *hdl = h; + hdl->mustupper = i; +} + +void +setshort_mustuniq(void *h, int i) +{ + mkshort_handle *hdl = h; + hdl->must_uniq = i; +} + + +char * +#ifdef DEBUG_MEM +MKSHORT(void *h, const char *istring, DEBUG_PARAMS ) +#else +mkshort(void *h, const char *istring) +#endif +{ + char *ostring = xxstrdup(istring, file, line); + char *nstring; + char *tstring; + char *cp; + char *np; + int i, l, nlen, replaced; + mkshort_handle *hdl = h; + + /* + * Whack leading "[Tt]he", + */ + if (( strlen(ostring) > hdl->target_len + 4) && + (strncmp(ostring, "The ", 4) == 0 || + strncmp(ostring, "the ", 4) == 0)) { + nstring = xxstrdup(ostring + 4, file, line); + xfree(ostring); + ostring = nstring; + } + + /* + * Look at the back of the string for " by BLAH" and whack + * it there. + */ + nstring = xxstrdup(ostring, file, line); + l = strlen (nstring); + while (l > 0) { + if (strncmp(&nstring[l], " by ",4) == 0) { + nstring[l] = 0; + break; + } + l --; + } + xfree(ostring); + ostring = nstring; + + if (!hdl->whitespaceok) { + /* + * Eliminate Whitespace + */ + tstring = xxstrdup(ostring, file, line); + l = strlen (tstring); + cp = ostring; + for (i=0;imustupper) { + for (tstring = ostring; *tstring; tstring++) { + *tstring = toupper(*tstring); + } + } + /* + * Eliminate chars on the blacklist. + * Characters that aren't ASCII are never OK. + */ + tstring = xxstrdup(ostring, file, line); + l = strlen (tstring); + cp = ostring; + for (i=0;ibadchars, tstring[i]) || !isascii(tstring[i])) + continue; + *cp++ = tstring[i]; + } + *cp = 0; + xfree(tstring); + + /* + * Toss vowels to approach target length, but don't toss them + * if we don't have to. We always keep the leading two letters + * to preserve leading vowels and some semblance of pronouncability. + * + * FIXME: There's a boundary case here where we're too aggressive. + * If the target length is "6" we will shorten "Trolley" to "Trlly", + * when we really don't have to. We should throw away one vowel, not + * both. + */ + + /* + * Delete vowels starting from the end. If it fits, quit stomping + * them. If we run out of string, give up. + */ + replaced = 1; + while (replaced && strlen(ostring) > hdl->target_len) { + ostring = delete_last_vowel(2, ostring, &replaced); + } + + /* + * Next to last thing, we look for trailing numbers and try to + * preserve those. This ensures that. + * Walk in the Woods 1. + * Walk in the Woods 2. + */ + np = ostring + strlen(ostring); + while (isdigit(*(np-1) )) { + np--; + } + if (np) { + nlen = strlen(np); + } + + /* + * Now brutally truncate the resulting string, preserve trailing + * numeric data. + */ + if ((/*i = */strlen(ostring)) > hdl->target_len) { + strcpy(&ostring[hdl->target_len] - strlen(np), np); + } + + if (hdl->must_uniq) { + return mkshort_add_to_list(hdl, ostring); + } + return ostring; +} + +#if 0 +char *foo[] = { +"VwthPst# 3700.706N 08627.588W 0000000m View the Past #2 ", +"PilotRoc 3655.270N 08717.173W 0000000m Pilot Rock by CacheAdvance ", +"MrCycsNg 3652.407N 08728.890W 0000000m Mr. Cayces Neighborhood by Ca", +"SOLDIER 3640.691N 08726.660W 0000000m SOLDIER’S TRIBUTE ", +"ZOOMZOOM 3636.659N 08721.793W 0000000m ZOOM ZOOM ZOOM by Feros Family", +"SOCLOSEB 3636.494N 08722.086W 0000000m SO CLOSE BUT YET by Kyle of Fe", +"InSrchfS 3636.363N 08636.363W 0000000m In Search of Steam by BigHank ", +"RdBlngSp 3632.119N 08550.956W 0000000m Red Boiling Springs by Firedog", +"HelngWtr 3631.729N 08550.481W 0000000m Healing Waters by FiredogPotte", +"AHHtheVi 3629.020N 08533.891W 0000000m ogPotter ", +"LstCrkCc 3628.167N 08801.656W 0000000m Lost Creek Cache by Paul Kathy", +"DlvrncTr 3626.412N 08729.249W 0000000m Deliverance Train by Team Skay", +"FrQrtrRn 3438.502N 08646.926W 0000000m Four Quarter Rendezvous by Zay", +"Jstlttlc 3620.647N 08814.298W 0000000m Just a little cache by Paul Ka", +"BrryPtch 3618.786N 08616.344W 0000000m Berry Patch Cache by White Dog", +"AStrllDw 3342.752N 08630.829W 0000000m A Stroll Down Memory Lane by t", +"QunfTnns 3606.413N 08651.962W 0000000m Queen of Tennessee by A182pilo", +"GoneFish 3618.199N 08655.171W 0000000m Gone Fishin' by White Dog Pack", +"GrnwysFn 3610.942N 08642.061W 0000000m Greenways Fence by Ukulele And", +"AStnsThr 3611.240N 08638.324W 0000000m A Stone's Throw by Murrcat & S", +"Nashvlls 3617.112N 08642.359W 0000000m Nashville's Zoo by White Dog P", +"BltzMcr4 3517.127N 08622.211W 0000000m Blitz Micro Number 4 by IHTFP ", +"NkdnthWn 3437.145N 08651.693W 0000000m Naked in the Wind by Zaybex ", +"ANcPlctR 3603.389N 08654.418W 0000000m A Nice Place to Rest by JoGPS ", +"welcomtT 3638.155N 08720.130W 0000000m welcome to TN by Raf of the se", +"welcomtK 3638.956N 08721.011W 0000000m welcome to KY by raf of the se", +"BltzMcr5 3506.191N 08634.277W 0000000m Blitz Micro Number 5 by IHTFP ", +"JmsFmlyG 3615.887N 08649.846W 0000000m James Family Grocery by White ", +"seekngrf 3629.262N 08742.333W 0000000m seekeing refuge by raf of the ", +"SecrtFll 3614.927N 08534.180W 0000000m Secret Falls ", +"ApstlcTh 3613.870N 08645.108W 0000000m Apostolic Thistle Walk by Jame", +"WllIllBD 3609.258N 08637.268W 0000000m Well....I'll Be \"Dammed\" byi", +"BettysBt 3608.857N 08550.564W 0000000m Betty's Booty by White Dog Pac", +"SmthngSm 3439.748N 08643.522W 0000000m Something Smells Fishy by Zayb", +"RckyRd(C 3605.315N 08549.326W 0000000m Rocky Road (Center Hill Lake) ", +"Brdwtchr 3436.605N 08651.243W 0000000m Birdwatcher's Dream by Zaybex ", +"JcksnsHl 3605.185N 08619.439W 0000000m Jackson's Halls by White Dog P", +"FrgttnP2 3509.599N 08633.282W 0000000m Forgotten Park 2 by mdawg & mu", +"SOLDIERS 3640.691N 08726.660W 0000000m SOLDIERS TRIBUTE by Feros Fami", +"EndofRop 3433.820N 08650.460W 0000000m End of Rope by Big Rock ", +"VwthPst1 3659.263N 08627.114W 0000000m View the Past #1 by wkgraham ", +"VwthPst2 3700.706N 08627.588W 0000000m View the Past #2 by wkgraham ", +"Trash#8 3603.102N 08655.144W 0000000m Cache In Trash Out # 8 ", +"SlwwwwCc 3602.543N 08535.953W 0000000m Sloowwww Cache by Tntcacher ", +"Leavttbv 3602.514N 08638.686W 0000000m Leave it to beaver by A182pilo", +"WhrrthHr 3436.594N 08654.759W 0000000m Where are the Horses? by Zaybe", +"ButtonCc 3433.401N 08645.294W 0000000m Button Cache by Zaybex ", +"MrcsLbrr 3436.842N 08655.972W 0000000m Marco's Library by Marco ", +"Octopus 3526.743N 08534.757W 0000000m Octopus by White Dog Pack ", +"WtrFllsV 3544.140N 08527.861W 0000000m Water Falls Valley by Cave Rat", +"DeddrpPn 3448.126N 08719.696W 0000000m Dead-drop Pink by Marco ", +"JWhlrRvr 3448.157N 08719.914W 0000000m Joe Wheeler River Walk by Marc", +"CvSprngs 3432.797N 08651.084W 0000000m Cave Springs Cache by Marco.. ", +"CnyFrkOv 3550.876N 08518.446W 0000000m Fork Overlook ", +"SheepsCa 3550.527N 08519.480W 0000000m Sheep's Cave ", +"VrgnFlls 3550.308N 08519.904W 0000000m Virgin Falls Cache ", +"ShrtctVr 3550.170N 08519.590W 0000000m Shortcut Virtual ", +"KlylFlls 3549.105N 08539.814W 0000000m Klaylee Falls Cache by pattytr", +"FshngfrB 3548.923N 08538.558W 0000000m BADGER by M&Mk ", +"TpfthHll 3548.808N 08601.722W 0000000m Top of the Hill Pet Cache by M", +"TwnFllsC 3548.560N 08537.996W 0000000m Twin Falls Cache by SLCREW a", +"WtchsCst 3548.197N 08537.673W 0000000m Witch's Castle Keys by SLCREW ", +"ThatCave 3544.901N 08522.854W 0000000m That Cave by JaDan150 and AprJ", +"BssltwnW 3541.174N 08801.489W 0000000m Busseltown Wildlife Refuge by ", +"Riverfrn 3540.968N 08546.995W 0000000m Riverfront by SLCREW and M&M", +"Basement 3540.086N 08521.304W 0000000m The Basement ", +"EfflTwrC 3617.132N 08818.371W 0000000m Eiffel Tower Cache by Dick Wan", +"KeyholeC 3544.562N 08524.098W 0000000m Keyhole Cave by Cave Rat ", +"(MC^2)Mn 3444.990N 08630.218W 0000000m (MC^2) Monte Sano Cuts Cache b", +"WildctCc 3636.823N 08808.087W 0000000m Wildcat Cache by The Storm ", +"NAlbm/Tn 3444.365N 08632.688W 0000000m N. Alabama / Tennessee Valley ", +"CalebsCa 3444.215N 08633.103W 0000000m Caleb's Cave by Papaw and Cale", +"MntSnPrs 3444.201N 08632.591W 0000000m Monte Sano Preserve by Evan & ", +"FltRckFl 3444.475N 08629.958W 0000000m Flat Rock Falls Cache by Jason", +"PanormCc 3443.961N 08631.638W 0000000m The Panorama Cache by IHTFP an", +"TnnssScv 3602.861N 08652.751W 0000000m Tennessee Scavenger Hunt Cache", +"Geocache 3435.209N 08655.968W 0000000m Geocache by Papaw & Caleb ", +"Skellig 3444.100N 08656.566W 0000000m Skellig by Zaybex ", +"Deceptio 3433.450N 08655.711W 0000000m Deception by Papaw and Caleb ", +"AwlknthD 3433.310N 08655.635W 0000000m A walk in the Desert by Papa", +"MiniMsQs 3558.934N 08650.674W 0000000m Mini Me's Quest by CrotalusRex", +"BakrsBlf 3541.891N 08717.300W 0000000m Bakers Bluff by Flower Child &", +"GoFlyAKi 3435.664N 08659.267W 0000000m Go Fly A Kite by Marco.. ", +"FlntCrkA 3432.028N 08656.806W 0000000m Flint Creek Adventure by Marco", +"HonordMn 3534.680N 08612.557W 0000000m Honored Mount by Southpaw ", +"SafariZo 3440.697N 08700.774W 0000000m Safari Zone by Zaybex ", +"JckDnlsC 3517.077N 08622.260W 0000000m Jack Daniels Cache by Rmearse ", +"FrgttnPr 3509.599N 08633.282W 0000000m Forgotten Park by mdawg & muff", +"DntOvrlk 3513.326N 08616.031W 0000000m Dont Overlook Me Cache ", +"ArYStmpd 3513.039N 08615.110W 0000000m Are You Stumped Yet? cache ", +"CchtthBn 3512.532N 08614.691W 0000000m Cache at the Bend ", +"Thtsnkng 3609.009N 08530.314W 0000000m That sinking feeling by Tntcac", +"GamersCc 3449.136N 08635.836W 0000000m mer's Cache by avoral ", +"CchMIfYC 3452.455N 08620.648W 0000000m Cache Me If You Can! by Glen H", +"SavageVs 3526.915N 08535.136W 0000000m Savage Vista by White Dog Pack", +"PrtrnG15 3555.479N 08653.274W 0000000m Praetorian Guards Hail Caesar #15!", +"WtrlnAmp 3443.722N 08632.535W 0000000m Waterline Amphitheater by Fath", +"BysLttlC 3447.569N 08638.448W 0000000m Boys' Little Cache by Zaybex ", +"DrgnsBrt 3443.779N 08635.188W 0000000m Dragon's Breath by Zaybex ", +"CryBbyHl 3430.733N 08657.362W 0000000m Cry Baby Hollow Cache by La Pa", +"Parmer 3606.218N 08651.590W 0000000m Parmer by A182pilot & Family ", +"JnnfrndJ 3438.141N 08632.991W 0000000m Jennifer and Jonathans Cliff C", +"ALDRIDGE 3435.305N 08632.868W 0000000m ALDRIDGE CREEK LOTTA LOOT!! by", +"RcktCtyS 3440.032N 08631.352W 0000000m Rocket City Stash by David Upt", +"TrgcAccd 3608.561N 08648.381W 0000000m Tragic Accident by Campaholics", +"FALLENTR 3439.210N 08631.104W 0000000m FALLEN TREE 4 MILE POST by zac", +"TrshOt15 3558.964N 08646.064W 0000000m Cache In Trash Out # 15 by Jo", +"TrshOt13 3602.214N 08650.428W 0000000m Cache In Trash Out #13 by JoGP", +"PrcysDrp 3604.312N 08653.465W 0000000m Percys Dripping Springs by KLi", +"TrshOt14 3605.292N 08648.560W 0000000m Cache In Trash Out # 14 by JoG", +"PrtrnGr5 3557.621N 08640.278W 0000000m Praetorian Guards Hail Caesar #5!", +"PrtrnGr4 3557.370N 08640.201W 0000000m Praetorian Guards Hail Caesar #4!", +"PrtrnGr3 3557.250N 08640.047W 0000000m Praetorian Guards Hail Caesar #3!", +"GrnMntnC 3439.120N 08631.100W 0000000m Green Mountain Cache by Steve ", +"TrshOt12 3605.330N 08635.817W 0000000m Cache In Trash Out #12 by JoGP", +"BlncngAc 3608.579N 08648.120W 0000000m Balancing Act by Campaholics ", +"DittoCac 3434.652N 08633.310W 0000000m Ditto Cache by mookey ", +"EraserCc 3431.888N 08633.024W 0000000m Eraser Cache by Zaybex ", +"FrMlPstE 3439.440N 08630.180W 0000000m Four Mile Post Extension Cache", +"MllrdFxC 3439.578N 08706.552W 0000000m Mallard-Fox Creek Cache by bam", +"FireCach 3443.908N 08630.318W 0000000m he by Glen Pam Chase M ", +"FlntRvrC 3443.170N 08625.990W 0000000m Flint River Canoe Cache by Ran", +"ArabinCc 3419.104N 08628.765W 0000000m The Arabian Cache by WesNSpace", +"CvrdBrdg 3412.406N 08659.392W 0000000m Covered Bridge Cache by pmarkh", +"MilesTCc 3424.470N 08611.720W 0000000m Miles Too Cache by Rmearse ", +"MbryOvrl 3423.803N 08611.922W 0000000m Mabrey Overlook Me by DDVaughn", +"LwEnfrcm 3423.218N 08612.258W 0000000m Law Enforcement Cache by DDVau", +"GrndDddy 3423.128N 08612.025W 0000000m Grand Daddys Home by Rmearse ", +"BamaCach 3421.459N 08611.686W 0000000m The Bama Cache by DDVaughn & T", +"Canyons 3440.085N 08600.910W 0000000m The Canyons by Aubrey and Josh", +"ADamGodV 3511.677N 08616.587W 0000000m A Dam Good View by mdawg & muf", +"UNDERTHE 3446.918N 08739.790W 0000000m UNDER THE ROCK by RUNNINGWILD ", +"SQUIRREL 3448.712N 08741.681W 0000000m SQUIRREL'S NEST by RUNNINGWILD", +"WlknthPr 3448.273N 08741.844W 0000000m Walk in the Park by Runningwil", +"NetsClue 3448.494N 08741.977W 0000000m Net's Clues by Runningwild Adv", +"NatrlBrd 3405.583N 08736.909W 0000000m Natural Bridge by Southeast Xt", +"TrnglPrk 3341.448N 08640.980W 0000000m Triangle Park Cache by Charles", +"LttlRvrI 3421.855N 08539.597W 0000000m Little River Initiative by spa", +"GimmShlt 3430.087N 08536.834W 0000000m Gimme Shelter by Big Rock & Po", +"GnomeTrs 3433.081N 08535.849W 0000000m Gnome Treasure by Big Rock ", +"FlyingTr 3608.594N 08648.179W 0000000m Flying Torso by Campaholics ", +"CultivtC 3608.582N 08648.064W 0000000m Cultivate a Cure by Campahol" +} +; + +main() +{ + char **foop = foo; + int r; + + printf("%s\n", mkshort("The Troll")); + printf("%s\n", mkshort("EFI")); + printf("%s\n", mkshort("the Troll")); + printf("%s\n", mkshort("the Trolley")); + printf("%s\n", mkshort("The Troll Lives Under The Bridge")); + printf("%s\n", mkshort("The \"Troll\" Lives Under $$ The Bridge!")); + printf("%s\n", mkshort("The Trolley Goes Round")); + printf("%s\n", mkshort("Cache In / Trash Out #1")); + printf("%s\n", mkshort("Cache In / Trash Out #2")); + printf("%s\n", mkshort("Cache In / Trash Out #137")); + + while (0 && *foop) { + printf("%s %s\n", mkshort(*foop+39), *foop+39); + foop++; + } + +printf("%s\n", delete_last_vowel(0, "the quick brown foo", &r)); +printf("%s\n", delete_last_vowel(0, "the quick brown fox", &r)); +printf("%s\n", delete_last_vowel(0, "xxx", &r)); +printf("%s\n", delete_last_vowel(0, "ixxx", &r)); +printf("%s\n", delete_last_vowel(0, "aexxx", &r)); + +} +#endif diff --git a/mkstyle.sh b/mkstyle.sh new file mode 100644 index 000000000..418e60f05 --- /dev/null +++ b/mkstyle.sh @@ -0,0 +1,21 @@ + +echo "/* This file is machine-generated from the contents of style/ */" +echo "/* by mkstyle.sh. Editing it by hand is an exeedingly bad idea. */" +echo + +nstyles="0" +for i in style/*.style +do + A=`basename $i | sed "s/.style$//"` + [ $A = "README" ] && continue + [ $A = "custom.style" ] && continue + ALIST="{ \"$A\", $A } , $ALIST" + echo "static char $A[] = " + sed 's/\\/\\\\/;s/"/\\"/g;s/\(^.\)/"\1/g;s/\(.$\)/\1\\n"/g' $i + echo ";" + nstyles=`expr $nstyles + 1`; +done + +echo "#include \"defs.h\"" +echo "style_vecs_t style_list[] = {$ALIST {0,0}};" +echo "size_t nstyles = $nstyles;" diff --git a/msvc/Expat/expat.h b/msvc/Expat/expat.h new file mode 100644 index 000000000..99678856d --- /dev/null +++ b/msvc/Expat/expat.h @@ -0,0 +1,1001 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef XmlParse_INCLUDED +#define XmlParse_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler +#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler +#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler +#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg +#endif + +#include + +#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) +#define XML_USE_MSC_EXTENSIONS 1 +#endif + +/* Expat tries very hard to make the API boundary very specifically + defined. There are two macros defined to control this boundary; + each of these can be defined before including this header to + achieve some different behavior, but doing so it not recommended or + tested frequently. + + XMLCALL - The calling convention to use for all calls across the + "library boundary." This will default to cdecl, and + try really hard to tell the compiler that's what we + want. + + XMLIMPORT - Whatever magic is needed to note that a function is + to be imported from a dynamically loaded library + (.dll, .so, or .sl, depending on your platform). + + The XMLCALL macro was added in Expat 1.95.7. The only one which is + expected to be directly useful in client code is XMLCALL. + + Note that on at least some Unix versions, the Expat library must be + compiled with the cdecl calling convention as the default since + system headers may assume the cdecl convention. +*/ +#ifndef XMLCALL +#if defined(XML_USE_MSC_EXTENSIONS) +#define XMLCALL __cdecl +#elif defined(__GNUC__) +#define XMLCALL __attribute__((cdecl)) +#else +/* For any platform which uses this definition and supports more than + one calling convention, we need to extend this definition to + declare the convention used on that platform, if it's possible to + do so. + + If this is the case for your platform, please file a bug report + with information on how to identify your platform via the C + pre-processor and how to specify the same calling convention as the + platform's malloc() implementation. +*/ +#define XMLCALL +#endif +#endif /* not defined XMLCALL */ + + +#if !defined(XML_STATIC) && !defined(XMLIMPORT) +#ifndef XML_BUILDING_EXPAT +/* using Expat from an application */ + +#ifdef XML_USE_MSC_EXTENSIONS +#define XMLIMPORT __declspec(dllimport) +#endif + +#endif +#endif /* not defined XML_STATIC */ + +/* If we didn't define it above, define it away: */ +#ifndef XMLIMPORT +#define XMLIMPORT +#endif + + +#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_UNICODE +#endif + +struct XML_ParserStruct; +typedef struct XML_ParserStruct *XML_Parser; + +#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ +#ifdef XML_UNICODE_WCHAR_T +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; +#else +typedef unsigned short XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE_WCHAR_T */ +#else /* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE */ + +/* Should this be defined using stdbool.h when C99 is available? */ +typedef unsigned char XML_Bool; +#define XML_TRUE ((XML_Bool) 1) +#define XML_FALSE ((XML_Bool) 0) + +/* The XML_Status enum gives the possible return values for several + API functions. The preprocessor #defines are included so this + stanza can be added to code that still needs to support older + versions of Expat 1.95.x: + + #ifndef XML_STATUS_OK + #define XML_STATUS_OK 1 + #define XML_STATUS_ERROR 0 + #endif + + Otherwise, the #define hackery is quite ugly and would have been + dropped. +*/ +enum XML_Status { + XML_STATUS_ERROR = 0, +#define XML_STATUS_ERROR XML_STATUS_ERROR + XML_STATUS_OK = 1 +#define XML_STATUS_OK XML_STATUS_OK +}; + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE, + XML_ERROR_ENTITY_DECLARED_IN_PE, + XML_ERROR_FEATURE_REQUIRES_XML_DTD, + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING, + XML_ERROR_UNBOUND_PREFIX +}; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ +typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +XMLPARSEAPI(void) +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" + keyword. The "isrequired" parameter will be true and the default + value will be NULL in the case of "#REQUIRED". If "isrequired" is + true and default is non-NULL, then this is a "#FIXED" default. +*/ +typedef void (XMLCALL *XML_AttlistDeclHandler) ( + void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +XMLPARSEAPI(void) +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + +/* The XML declaration handler is called for *both* XML declarations + and text declarations. The way to distinguish is that the version + parameter will be NULL for text declarations. The encoding + parameter may be NULL for XML declarations. The standalone + parameter will be -1, 0, or 1 indicating respectively that there + was no standalone parameter in the declaration, that it was given + as no, or that it was given as yes. +*/ +typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +XMLPARSEAPI(void) +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(XMLCALL *malloc_fcn)(size_t size); + void *(XMLCALL *realloc_fcn)(void *ptr, size_t size); + void (XMLCALL *free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the + external protocol or NULL if there is none specified. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type + names and attribute names that belong to a namespace will be + expanded; unprefixed attribute names are never expanded; unprefixed + element type names are expanded only if there is a default + namespace. The expanded name is the concatenation of the namespace + URI, the namespace separator character, and the local part of the + name. If the namespace separator is '\0' then the namespace URI + and the local part will be concatenated without any separator. + When a namespace is not declared, the name and prefix will be + passed through without expansion. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suite referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* Prepare a parser object to be re-used. This is particularly + valuable when memory allocation overhead is disproportionatly high, + such as when a large number of small documnents need to be parsed. + All handlers are cleared from the parser, except for the + unknownEncodingHandler. The parser's external state is re-initialized + except for the values of ns and ns_triplets. + + Added in Expat 1.95.3. +*/ +XMLPARSEAPI(XML_Bool) +XML_ParserReset(XML_Parser parser, const XML_Char *encoding); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. +*/ +typedef void (XMLCALL *XML_StartElementHandler) (void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (XMLCALL *XML_EndElementHandler) (void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (XMLCALL *XML_ProcessingInstructionHandler) ( + void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (XMLCALL *XML_CommentHandler) (void *userData, + const XML_Char *data); + +typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData); +typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData); + +/* This is called for any characters in the XML document for which + there is no applicable handler. This includes both characters that + are part of markup which is of a kind that is not reported + (comments, markup declarations), or characters that are part of a + construct which could be reported but for which no handler has been + supplied. The characters are passed exactly as they were in the XML + document except that they will be encoded in UTF-8 or UTF-16. + Line boundaries are not normalized. Note that a byte order mark + character is not passed to the default handler. There are no + guarantees about how characters are divided between calls to the + default handler: for example, a comment might be split between + multiple calls. +*/ +typedef void (XMLCALL *XML_DefaultHandler) (void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. +*/ +typedef void (XMLCALL *XML_StartDoctypeDeclHandler) ( + void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset); + +/* This is called for the start of the DOCTYPE declaration when the + closing > is encountered, but after processing any external + subset. +*/ +typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (), value will + be non-NULL and systemId, publicID, and notationName will be NULL. + The value string is NOT nul-terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be NULL and systemId will be + non-NULL. The publicId argument will be NULL unless a public + identifier was provided. The notationName argument will have a + non-NULL value only for unparsed entity declarations. + + Note that is_parameter_entity can't be changed to XML_Bool, since + that would break binary compatibility. +*/ +typedef void (XMLCALL *XML_EntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +XMLPARSEAPI(void) +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. + + This is called for a declaration of an unparsed (NDATA) entity. + The base argument is whatever was set by XML_SetBase. The + entityName, systemId and notationName arguments will never be + NULL. The other arguments may be. +*/ +typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. The base argument is + whatever was set by XML_SetBase. The notationName will never be + NULL. The other arguments can be. +*/ +typedef void (XMLCALL *XML_NotationDeclHandler) ( + void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for + each namespace declaration. The call to the start and end element + handlers occur between the calls to the start and end namespace + declaration handlers. For an xmlns attribute, prefix will be + NULL. For an xmlns="" attribute, uri will be NULL. +*/ +typedef void (XMLCALL *XML_StartNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (XMLCALL *XML_EndNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone, that is, it has an + external subset or a reference to a parameter entity, but does not + have standalone="yes". If this handler returns XML_STATUS_ERROR, + then processing will not continue, and the parser will return a + XML_ERROR_NOT_STANDALONE error. + If parameter entity parsing is enabled, then in addition to the + conditions above this handler will only be called if the referenced + entity was actually read. +*/ +typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData); + +/* This is called for a reference to an external parsed general + entity. The referenced entity is not automatically parsed. The + application can parse it immediately or later using + XML_ExternalEntityParserCreate. + + The parser argument is the parser parsing the entity containing the + reference; it can be passed as the parser argument to + XML_ExternalEntityParserCreate. The systemId argument is the + system identifier as specified in the entity declaration; it will + not be NULL. + + The base argument is the system identifier that should be used as + the base for resolving systemId if systemId was relative; this is + set by XML_SetBase; it may be NULL. + + The publicId argument is the public identifier as specified in the + entity declaration, or NULL if none was specified; the whitespace + in the public identifier will have been normalized as required by + the XML spec. + + The context argument specifies the parsing context in the format + expected by the context argument to XML_ExternalEntityParserCreate; + context is valid only until the handler returns, so if the + referenced entity is to be parsed later, it must be copied. + context is NULL only when the entity is a parameter entity. + + The handler should return XML_STATUS_ERROR if processing should not + continue because of a fatal error in the handling of the external + entity. In this case the calling parser will return an + XML_ERROR_EXTERNAL_ENTITY_HANDLING error. + + Note that unlike other handlers the first argument is the parser, + not userData. +*/ +typedef int (XMLCALL *XML_ExternalEntityRefHandler) ( + XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This is called in two situations: + 1) An entity reference is encountered for which no declaration + has been read *and* this is not an error. + 2) An internal entity reference is read, but not expanded, because + XML_SetDefaultHandler has been called. + Note: skipped parameter entities in declarations and skipped general + entities in attribute values cannot be reported, because + the event would be out of sync with the reporting of the + declarations or attribute values +*/ +typedef void (XMLCALL *XML_SkippedEntityHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity); + +/* This structure is filled in by the XML_UnknownEncodingHandler to + provide information to the parser about encodings that are unknown + to the parser. + + The map[b] member gives information about byte sequences whose + first byte is b. + + If map[b] is c where c is >= 0, then b by itself encodes the + Unicode scalar value c. + + If map[b] is -1, then the byte sequence is malformed. + + If map[b] is -n, where n >= 2, then b is the first byte of an + n-byte sequence that encodes a single Unicode scalar value. + + The data member will be passed as the first argument to the convert + function. + + The convert function is used to convert multibyte sequences; s will + point to a n-byte sequence where map[(unsigned char)*s] == -n. The + convert function must return the Unicode scalar value represented + by this byte sequence or -1 if the byte sequence is malformed. + + The convert function may be NULL if the encoding is a single-byte + encoding, that is if map[b] >= -1 for all bytes b. + + When the parser is finished with the encoding, then if release is + not NULL, it will call release passing it the data member; once + release has been called, the convert function will not be called + again. + + Expat places certain restrictions on the encodings that are supported + using this mechanism. + + 1. Every ASCII character that can appear in a well-formed XML document, + other than the characters + + $@\^`{}~ + + must be represented by a single byte, and that byte must be the + same byte that represents that character in ASCII. + + 2. No character may require more than 4 bytes to encode. + + 3. All characters encoded must have Unicode scalar values <= + 0xFFFF, (i.e., characters that would be encoded by surrogates in + UTF-16 are not allowed). Note that this restriction doesn't + apply to the built-in support for UTF-8 and UTF-16. + + 4. No Unicode character may be encoded by more than one distinct + sequence of bytes. +*/ +typedef struct { + int map[256]; + void *data; + int (XMLCALL *convert)(void *data, const char *s); + void (XMLCALL *release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. + + The encodingHandlerData argument is that which was passed as the + second argument to XML_SetUnknownEncodingHandler. + + The name argument gives the name of the encoding as specified in + the encoding declaration. + + If the callback can provide information about the encoding, it must + fill in the XML_Encoding structure, and return XML_STATUS_OK. + Otherwise it must return XML_STATUS_ERROR. + + If info does not describe a suitable encoding, then the parser will + return an XML_UNKNOWN_ENCODING error. +*/ +typedef int (XMLCALL *XML_UnknownEncodingHandler) ( + void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +XMLPARSEAPI(void) +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +XMLPARSEAPI(void) +XML_SetStartElementHandler(XML_Parser, XML_StartElementHandler); + +XMLPARSEAPI(void) +XML_SetEndElementHandler(XML_Parser, XML_EndElementHandler); + +XMLPARSEAPI(void) +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +XMLPARSEAPI(void) +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +XMLPARSEAPI(void) +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +XMLPARSEAPI(void) +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +XMLPARSEAPI(void) +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +XMLPARSEAPI(void) +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of + internal entities. These entity references will be passed to the + default handler, or to the skipped entity handler, if one is set. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of + internal entities. The entity reference will not be passed to the + default handler. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +XMLPARSEAPI(void) +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-NULL value for arg is specified here, then it will be + passed as the first argument to the external entity ref handler + instead of the parser object. +*/ +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg); + +XMLPARSEAPI(void) +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler); + +XMLPARSEAPI(void) +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end + element, processing instruction or character data. It causes the + corresponding markup to be passed to the default handler. +*/ +XMLPARSEAPI(void) +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single string separated by + the separator character specified when the parser was created: URI + + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the name + has a prefix. + + Note: Calling XML_SetReturnNSTriplet after XML_Parse or + XML_ParseBuffer has no effect. +*/ + +XMLPARSEAPI(void) +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +XMLPARSEAPI(void) +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or NULL. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument to + XML_ParserCreate. On success XML_SetEncoding returns non-zero, + zero otherwise. + Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer + has no effect and returns XML_STATUS_ERROR. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed as the + first argument to callbacks instead of userData. The userData will + still be accessible using XML_GetUserData. +*/ +XMLPARSEAPI(void) +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* If useDTD == XML_TRUE is passed to this function, then the parser + will assume that there is an external subset, even if none is + specified in the document. In such a case the parser will call the + externalEntityRefHandler with a value of NULL for the systemId + argument (the publicId and context arguments will be NULL as well). + Note: If this function is called, then this must be done before + the first call to XML_Parse or XML_ParseBuffer, since it will + have no effect after that. Returns + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING. + Note: If the document does not have a DOCTYPE declaration at all, + then startDoctypeDeclHandler and endDoctypeDeclHandler will not + be called, despite an external subset being parsed. + Note: If XML_DTD is not defined when Expat is compiled, returns + XML_ERROR_FEATURE_REQUIRES_XML_DTD. +*/ +XMLPARSEAPI(enum XML_Error) +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD); + + +/* Sets the base to be used for resolving relative URIs in system + identifiers in declarations. Resolving relative identifiers is + left to the application: this value will be passed through as the + base argument to the XML_ExternalEntityRefHandler, + XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base + argument will be copied. Returns XML_STATUS_ERROR if out of memory, + XML_STATUS_OK otherwise. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetBase(XML_Parser parser, const XML_Char *base); + +XMLPARSEAPI(const XML_Char *) +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call + to the XML_StartElementHandler that were specified in the start-tag + rather than defaulted. Each attribute/value pair counts as 2; thus + this correspondds to an index into the atts array passed to the + XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to + XML_StartElementHandler, or -1 if there is no ID attribute. Each + attribute/value pair counts as 2; thus this correspondds to an + index into the atts array passed to the XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is + detected. The last call to XML_Parse must have isFinal true; len + may be zero for this call (or any other). + + Though the return values for these functions has always been + described as a Boolean value, the implementation, at least for the + 1.95.x series, has always returned exactly one of the XML_Status + values. +*/ +XMLPARSEAPI(enum XML_Status) +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +XMLPARSEAPI(void *) +XML_GetBuffer(XML_Parser parser, int len); + +XMLPARSEAPI(enum XML_Status) +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Creates an XML_Parser object that can parse an external general + entity; context is a '\0'-terminated string specifying the parse + context; encoding is a '\0'-terminated string giving the name of + the externally specified encoding, or NULL if there is no + externally specified encoding. The context string consists of a + sequence of tokens separated by formfeeds (\f); a token consisting + of a name specifies that the general entity of the name is open; a + token of the form prefix=uri specifies the namespace for a + particular prefix; a token of the form =uri specifies the default + namespace. This can be called at any point after the first call to + an ExternalEntityRefHandler so longer as the parser has not yet + been freed. The new parser is completely independent and may + safely be used in a separate thread. The handlers and userData are + initialized from the parser argument. Returns NULL if out of memory. + Otherwise returns a new XML_Parser object. +*/ +XMLPARSEAPI(XML_Parser) +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD + subset). If parsing of parameter entities is enabled, then + references to external parameter entities (including the external + DTD subset) will be passed to the handler set with + XML_SetExternalEntityRefHandler. The context passed will be 0. + + Unlike external general entities, external parameter entities can + only be parsed synchronously. If the external parameter entity is + to be parsed, it must be parsed during the call to the external + entity ref handler: the complete sequence of + XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and + XML_ParserFree calls must be made during this call. After + XML_ExternalEntityParserCreate has been called to create the parser + for the external parameter entity (context must be 0 for this + call), it is illegal to make any calls on the old parser until + XML_ParserFree has been called on the newly created parser. + If the library has been compiled without support for parameter + entity parsing (ie without XML_DTD being defined), then + XML_SetParamEntityParsing will return 0 if parsing of parameter + entities is requested; otherwise it will return non-zero. + Note: If XML_SetParamEntityParsing is called after XML_Parse or + XML_ParseBuffer, then it has no effect and will always return 0. +*/ +XMLPARSEAPI(int) +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then + XML_GetErrorCode returns information about the error. +*/ +XMLPARSEAPI(enum XML_Error) +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse + location. They may be called from any callback called to report + some parse event; in this case the location is the location of the + first of the sequence of characters that generated the event. When + called from callbacks generated by declarations in the document + prologue, the location identified isn't as neatly defined, but will + be within the relevant markup. When called outside of the callback + functions, the position indicated will be just past the last parse + event (regardless of whether there was an associated callback). + + They may also be called after returning from a call to XML_Parse + or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then + the location is the location of the character at which the error + was detected; otherwise the location is the location of the last + parse event, as described above. +*/ +XMLPARSEAPI(int) XML_GetCurrentLineNumber(XML_Parser parser); +XMLPARSEAPI(int) XML_GetCurrentColumnNumber(XML_Parser parser); +XMLPARSEAPI(long) XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. + Returns 0 if the event is in an internal entity. +*/ +XMLPARSEAPI(int) +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a NULL pointer. Also returns a NULL pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. +*/ +XMLPARSEAPI(const char *) +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees the content model passed to the element declaration handler */ +XMLPARSEAPI(void) +XML_FreeContentModel(XML_Parser parser, XML_Content *model); + +/* Exposing the memory handling functions used in Expat */ +XMLPARSEAPI(void *) +XML_MemMalloc(XML_Parser parser, size_t size); + +XMLPARSEAPI(void *) +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size); + +XMLPARSEAPI(void) +XML_MemFree(XML_Parser parser, void *ptr); + +/* Frees memory used by the parser. */ +XMLPARSEAPI(void) +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +XMLPARSEAPI(const XML_LChar *) +XML_ErrorString(enum XML_Error code); + +/* Return a string containing the version number of this expat */ +XMLPARSEAPI(const XML_LChar *) +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat. +*/ +XMLPARSEAPI(XML_Expat_Version) +XML_ExpatVersionInfo(void); + +/* Added in Expat 1.95.5. */ +enum XML_FeatureEnum { + XML_FEATURE_END = 0, + XML_FEATURE_UNICODE, + XML_FEATURE_UNICODE_WCHAR_T, + XML_FEATURE_DTD, + XML_FEATURE_CONTEXT_BYTES, + XML_FEATURE_MIN_SIZE, + XML_FEATURE_SIZEOF_XML_CHAR, + XML_FEATURE_SIZEOF_XML_LCHAR + /* Additional features must be added to the end of this enum. */ +}; + +typedef struct { + enum XML_FeatureEnum feature; + const XML_LChar *name; + long int value; +} XML_Feature; + +XMLPARSEAPI(const XML_Feature *) +XML_GetFeatureList(void); + + +/* Expat follows the GNU/Linux convention of odd number minor version for + beta/development releases and even number minor version for stable + releases. Micro is bumped with each release, and set to 0 with each + change to major or minor version. +*/ +#define XML_MAJOR_VERSION 1 +#define XML_MINOR_VERSION 95 +#define XML_MICRO_VERSION 7 + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlParse_INCLUDED */ diff --git a/msvc/Expat/libexpat.dll b/msvc/Expat/libexpat.dll new file mode 100644 index 0000000000000000000000000000000000000000..4c925de3579d7bc74ea0c85f4d096d0070e09da1 GIT binary patch literal 143360 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

o`}M#~TH!R_w*#*Mmjd$$ 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 Gf%{*geonRk literal 0 HcmV?d00001 diff --git a/msvc/GPSBabel.dsp b/msvc/GPSBabel.dsp new file mode 100644 index 000000000..5b1ab443d --- /dev/null +++ b/msvc/GPSBabel.dsp @@ -0,0 +1,645 @@ +# Microsoft Developer Studio Project File - Name="GPSBabel" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=GPSBabel - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GPSBabel.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GPSBabel.mak" CFG="GPSBabel - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GPSBabel - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "GPSBabel - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "expat" /I "..\coldsync" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__WIN32__" /D VERSION=\"1.2.1_beta01072004_msvc\" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "expat" /I "..\coldsync" /D "WIN32" /D "__WIN32__" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D VERSION=\"1.2.1_beta01072004_msvc\" /FR /YX /FD /GZ /c +# SUBTRACT CPP /WX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "GPSBabel - Win32 Release" +# Name "GPSBabel - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "Jeeps" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\jeeps\gpsapp.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Jeeps" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Jeeps" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpscom.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Jeeps" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Jeeps" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsmath.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Jeeps" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Jeeps" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsmem.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Jeeps" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Jeeps" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsprot.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Jeeps" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Jeeps" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsread.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Jeeps" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Jeeps" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsrqst.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Jeeps" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Jeeps" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpssend.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Jeeps" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Jeeps" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsserial.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Jeeps" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Jeeps" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsutil.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Jeeps" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Jeeps" + +!ENDIF + +# End Source File +# End Group +# Begin Group "Coldsync" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\coldsync\pdb.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Coldsync" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Coldsync" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\coldsync\util.c + +!IF "$(CFG)" == "GPSBabel - Win32 Release" + +# PROP Intermediate_Dir "Release\Coldsync" + +!ELSEIF "$(CFG)" == "GPSBabel - Win32 Debug" + +# PROP Intermediate_Dir "Debug\Coldsync" + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=..\arcdist.c +# End Source File +# Begin Source File + +SOURCE=..\cetus.c +# End Source File +# Begin Source File + +SOURCE=..\copilot.c +# End Source File +# Begin Source File + +SOURCE=..\csv_util.c +# End Source File +# Begin Source File + +SOURCE=..\delgpl.c +# End Source File +# Begin Source File + +SOURCE=..\duplicate.c +# End Source File +# Begin Source File + +SOURCE=..\easygps.c +# End Source File +# Begin Source File + +SOURCE=..\filter_vecs.c +# End Source File +# Begin Source File + +SOURCE=..\garmin.c +# End Source File +# Begin Source File + +SOURCE=..\gcdb.c +# End Source File +# Begin Source File + +SOURCE=..\geo.c +# End Source File +# Begin Source File + +SOURCE=..\geoniche.c +# End Source File +# Begin Source File + +SOURCE=..\gpilots.c +# End Source File +# Begin Source File + +SOURCE=..\gpspilot.c +# End Source File +# Begin Source File + +SOURCE=..\gpsutil.c +# End Source File +# Begin Source File + +SOURCE=..\gpx.c +# End Source File +# Begin Source File + +SOURCE=..\grtcirc.c +# End Source File +# Begin Source File + +SOURCE=..\holux.c +# End Source File +# Begin Source File + +SOURCE=..\hsa_ndv.c +# End Source File +# Begin Source File + +SOURCE=..\html.c +# End Source File +# Begin Source File + +SOURCE=..\internal_styles.c +# End Source File +# Begin Source File + +SOURCE=..\magnav.c +# End Source File +# Begin Source File + +SOURCE=..\magproto.c +# End Source File +# Begin Source File + +SOURCE=..\main.c +# End Source File +# Begin Source File + +SOURCE=..\mapopolis.c +# End Source File +# Begin Source File + +SOURCE=..\mapsend.c +# End Source File +# Begin Source File + +SOURCE=..\mapsource.c +# End Source File +# Begin Source File + +SOURCE=..\mkshort.c +# End Source File +# Begin Source File + +SOURCE=..\navicache.c +# End Source File +# Begin Source File + +SOURCE=..\netstumbler.c +# End Source File +# Begin Source File + +SOURCE=..\nmea.c +# End Source File +# Begin Source File + +SOURCE=..\ozi.c +# End Source File +# Begin Source File + +SOURCE=..\palmdoc.c +# End Source File +# Begin Source File + +SOURCE=..\pcx.c +# End Source File +# Begin Source File + +SOURCE=..\polygon.c +# End Source File +# Begin Source File + +SOURCE=..\position.c +# End Source File +# Begin Source File + +SOURCE=..\psitrex.c +# End Source File +# Begin Source File + +SOURCE=..\psp.c +# End Source File +# Begin Source File + +SOURCE=..\queue.c +# End Source File +# Begin Source File + +SOURCE=..\quovadis.c +# End Source File +# Begin Source File + +SOURCE=..\reverse_route.c +# End Source File +# Begin Source File + +SOURCE=..\route.c +# End Source File +# Begin Source File + +SOURCE=..\saroute.c +# End Source File +# Begin Source File + +SOURCE=..\smplrout.c +# End Source File +# Begin Source File + +SOURCE=..\sort.c +# End Source File +# Begin Source File + +SOURCE=..\text.c +# End Source File +# Begin Source File + +SOURCE=..\tiger.c +# End Source File +# Begin Source File + +SOURCE=..\tmpro.c +# End Source File +# Begin Source File + +SOURCE=..\tpg.c +# End Source File +# Begin Source File + +SOURCE=..\util.c +# End Source File +# Begin Source File + +SOURCE=..\util_crc.c +# End Source File +# Begin Source File + +SOURCE=..\vecs.c +# End Source File +# Begin Source File + +SOURCE=..\vmem.c +# End Source File +# Begin Source File + +SOURCE=..\waypt.c +# End Source File +# Begin Source File + +SOURCE=..\xcsv.c +# End Source File +# Begin Source File + +SOURCE=.\Expat\libexpat.lib +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "Coldsync-Headers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\coldsync\config.h +# End Source File +# Begin Source File + +SOURCE=..\coldsync\palm.h +# End Source File +# Begin Source File + +SOURCE=..\coldsync\pdb.h +# End Source File +# Begin Source File + +SOURCE=..\coldsync\pconn\util.h +# End Source File +# End Group +# Begin Group "Jeeps-Headers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\jeeps\gps.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsapp.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpscom.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsdatum.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsfmt.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsinput.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsmath.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsmem.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsnmea.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsnmeafmt.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsnmeaget.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsport.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsproj.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsprot.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsread.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsrqst.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpssend.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsserial.h +# End Source File +# Begin Source File + +SOURCE=..\jeeps\gpsutil.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\csv_util.h +# End Source File +# Begin Source File + +SOURCE=..\defs.h +# End Source File +# Begin Source File + +SOURCE=..\garmin_tables.h +# End Source File +# Begin Source File + +SOURCE=..\grtcirc.h +# End Source File +# Begin Source File + +SOURCE=..\holux.h +# End Source File +# Begin Source File + +SOURCE=..\magellan.h +# End Source File +# Begin Source File + +SOURCE=..\mapsend.h +# End Source File +# Begin Source File + +SOURCE=..\queue.h +# End Source File +# Begin Source File + +SOURCE=..\quovadis.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/msvc/GPSBabel.dsw b/msvc/GPSBabel.dsw new file mode 100644 index 000000000..622d699e8 --- /dev/null +++ b/msvc/GPSBabel.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "GPSBabel"=.\GPSBabel.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/msvc/GPSBabel.sln b/msvc/GPSBabel.sln new file mode 100644 index 000000000..3748f751f --- /dev/null +++ b/msvc/GPSBabel.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GPSBabel", "GPSBabel.vcproj", "{EB2609DB-5800-45B2-BCB2-06D72F389DCA}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {EB2609DB-5800-45B2-BCB2-06D72F389DCA}.Debug.ActiveCfg = Debug|Win32 + {EB2609DB-5800-45B2-BCB2-06D72F389DCA}.Debug.Build.0 = Debug|Win32 + {EB2609DB-5800-45B2-BCB2-06D72F389DCA}.Release.ActiveCfg = Release|Win32 + {EB2609DB-5800-45B2-BCB2-06D72F389DCA}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/msvc/GPSBabel.vcproj b/msvc/GPSBabel.vcproj new file mode 100644 index 000000000..8d9f72aea --- /dev/null +++ b/msvc/GPSBabel.vcproj @@ -0,0 +1,1717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/README.msvc b/msvc/README.msvc new file mode 100644 index 000000000..373e22a77 --- /dev/null +++ b/msvc/README.msvc @@ -0,0 +1,26 @@ + +BUILDING GPSBABEL WITH Microsoft Visual C++: + +This directory contains the necessary files to build GPSBabel with +Microsoft Visual C++ version 6.0 and above. The project and workspace +files should just work, provided that the "msvc" directory is a direct +child of the directory that contains the GPSBabel source. (This is where +it should be, by default, so you shouldn't have to do anything other than +load the workspace and hit "build all.") If you load these files in to +Visual Studio .NET, you may be asked to convert them to the new format; +In that case, you should do so. + +The "Expat" directory contains the import library and header file for the +Expat DLL. This may or may not be the latest build of Expat; you might +want to check http://expat.sourceforge.net to see if there is a more recent +version. + +To run GPSBabel, you must make sure that the libexpat.dll from the Expat +directory is in the DLL search path. The easiest way to do this, and to +avoid version conflicts with other programs that use expat, is to put +libexpat.dll in the same directory as gpsbabel.exe. + +If you experience any problems with this project file or with the build +process, please ask for assistance on the gpsbabel-code mailing list at +http://lists.sourceforge.net/lists/listinfo/gpsbabel-code . + diff --git a/navicache.c b/navicache.c new file mode 100644 index 000000000..0d42a38ba --- /dev/null +++ b/navicache.c @@ -0,0 +1,267 @@ +/* + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include "defs.h" +#if !NO_EXPAT +#include +static XML_Parser psr; +#endif + +static waypoint *wpt_tmp; + +FILE *fd; +FILE *ofd; + +static char *noretired = NULL; + +static +arglist_t nav_args[] = { + {"noretired", &noretired, "Suppress retired geocaches.", + NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + +#define MYNAME "navicache" +#define MY_CBUF 4096 + +#if NO_EXPAT +void +nav_rd_init(const char *fname) +{ + fatal(MYNAME ": This build excluded GPX support because expat was not installed.\n"); +} + +void +nav_read(void) +{ +} +#else + +struct +nc_type_mapping{ + geocache_type type; + const char *name; +} nc_type_map[] = { + { gt_unknown, "unknown" }, + { gt_traditional, "normal" }, + { gt_multi, "Multi-part" }, + { gt_virtual, "Virtual" }, + { gt_event, "event" } +}; + +struct +nc_container_mapping{ + geocache_container type; + const char *name; +} nc_container_map[] = { + { gc_other, "Unknown" }, + { gc_micro, "Micro" }, + { gc_regular, "Normal" }, + { gc_large, "Large" }, + { gc_virtual, "Virtual" } +}; + +static +geocache_type +nc_mktype(const char *t) +{ + int i; + int sz = sizeof(nc_type_map) / sizeof(nc_type_map[0]); + + for (i = 0; i < sz; i++) { + if (0 == case_ignore_strcmp(t, nc_type_map[i].name)) { + return nc_type_map[i].type; + } + } + return gt_unknown; +} + +static +geocache_container +nc_mkcont(const char *t) +{ + int i; + int sz = sizeof(nc_container_map) / sizeof(nc_container_map[0]); + + for (i = 0; i < sz; i++) { + if (0 == case_ignore_strcmp(t, nc_container_map[i].name)) { + return nc_container_map[i].type; + } + } + return gc_unknown; +} + +static void +nav_start(void *data, const char *el, const char **attr) +{ + if (0 == strcmp(el, "CacheDetails")) { + const char **ap; + wpt_tmp = waypt_new(); + for (ap = attr; *ap; ap+=2) { + if (0 == strcmp(ap[0], "cache_id")) { + wpt_tmp->shortname = xstrdup(ap[1]); + } else + if (0 == strcmp(ap[0], "name")) { + wpt_tmp->description = xstrdup(ap[1]); + } else + if (0 == strcmp(ap[0], "latitude")) { + sscanf(ap[1], "%lf", + &wpt_tmp->latitude); + } else + if (0 == strcmp(ap[0], "longitude")) { + sscanf(ap[1], "%lf", + &wpt_tmp->longitude); + } else + if (0 == strcmp(ap[0], "longitude")) { + sscanf(ap[1], "%lf", + &wpt_tmp->longitude); + } else + if (0 == strcmp(ap[0], "difficulty")) { + float x; + sscanf(ap[1], "%f", &x); + wpt_tmp->gc_data.diff = x * 10; + } else + if (0 == strcmp(ap[0], "terrain")) { + float x; + sscanf(ap[1], "%f", &x); + wpt_tmp->gc_data.terr = x * 10; + } else + if (0 == strcmp(ap[0], "cache_type")) { + static char buf[512]; + + wpt_tmp->gc_data.type = nc_mktype(ap[1]); + if (!strcmp(ap[1], "normal")) + wpt_tmp->icon_descr = "Geocache-regular"; + else if (!strcmp(ap[1], "multi-part")) + wpt_tmp->icon_descr = "Geocache-multi"; + else if (!strcmp(ap[1], "moving_travelling")) + wpt_tmp->icon_descr = "Geocache-moving"; + else { + sprintf(buf, "Geocache-%-.20s", ap[1]); + wpt_tmp->icon_descr = xstrdup(buf); + } + } else + if (0 == strcmp(ap[0], "hidden_date")) { + struct tm tm; + + sscanf(ap[1], "%d-%d-%d", + &tm.tm_year, + &tm.tm_mon, + &tm.tm_mday); + tm.tm_mon -= 1; + tm.tm_year -= 1900; + tm.tm_isdst = 0; + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + wpt_tmp->creation_time = mktime(&tm); + } else + if (0 == strcmp(ap[0], "retired")) { + if (!strcmp(ap[1], "yes") && noretired) { + xfree(wpt_tmp); + return; + } + } else + if (0 == strcmp(ap[0], "cache_size")) { + wpt_tmp->gc_data.container = nc_mkcont(ap[1]); + } else + if (0 == strcmp(ap[0], "description")) { + wpt_tmp->gc_data.desc_long.is_html = 1; + wpt_tmp->gc_data.desc_long.utfstring = xstrdup(ap[1]); + } else + if (0 == strcmp(ap[0], "comments")) { + wpt_tmp->gc_data.desc_short.is_html = 1; + wpt_tmp->gc_data.desc_short.utfstring = xstrdup(ap[1]); + } + } + waypt_add(wpt_tmp); + } +} + +static void +nav_end(void *data, const char *el) +{ +} + +void +nav_rd_init(const char *fname) +{ + fd = xfopen(fname, "r", MYNAME); + + psr = XML_ParserCreate(NULL); + if (!psr) { + fatal(MYNAME ":Cannot create XML parser\n"); + } + + XML_SetElementHandler(psr, nav_start, nav_end); +} + +void +nav_read(void) +{ + int len; + char buf[MY_CBUF]; + + while ((len = fread(buf, 1, sizeof(buf), fd))) { + if (!XML_Parse(psr, buf, len, feof(fd))) { + fatal(MYNAME ":Parse error at %d: %s\n", + XML_GetCurrentLineNumber(psr), + XML_ErrorString(XML_GetErrorCode(psr))); + } + } + + XML_ParserFree(psr); +} + +#endif + +void +nav_rd_deinit(void) +{ + fclose(fd); +} + +void +nav_wr_init(const char *fname) +{ + fatal(MYNAME ": Does not support writing Navicache files.\n"); + ofd = xfopen(fname, "w", MYNAME); +} + +void +nav_wr_deinit(void) +{ + fclose(ofd); +} + +void +nav_write(void) +{ +} + +ff_vecs_t navicache_vecs = { + ff_type_file, + nav_rd_init, + nav_wr_init, + nav_rd_deinit, + nav_wr_deinit, + nav_read, + nav_write, + NULL, + nav_args, +}; diff --git a/netstumbler.c b/netstumbler.c new file mode 100644 index 000000000..1674215e6 --- /dev/null +++ b/netstumbler.c @@ -0,0 +1,304 @@ +/* + Read Netstumbler data files. + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net and + John Temples; gpsns@xargs.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "csv_util.h" +#include + +static FILE *file_in; +static char *nseicon = NULL; +static char *nsneicon = NULL; +static char *seicon = NULL; +static char *sneicon = NULL; +static char *snmac = NULL; + +static void fix_netstumbler_dupes(void); + +#define MYNAME "NETSTUMBLER" + +static +arglist_t netstumbler_args[] = { + {"nseicon", &nseicon, "Non-stealth encrypted icon name", + "Red Square", ARGTYPE_STRING }, + {"nsneicon", &nsneicon, "Non-stealth non-encrypted icon name", + "Green Square", ARGTYPE_STRING }, + {"seicon", &seicon, "Stealth encrypted icon name", + "Red Diamond", ARGTYPE_STRING }, + {"sneicon", &sneicon, "Stealth non-encrypted icon name", + "Green Diamond", ARGTYPE_STRING }, + {"snmac", &snmac, "Shortname is MAC address", NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "r", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); +} + +static void +data_read(void) +{ + char ibuf[512]; + char ssid[2 + 32 + 2 + 1]; /* "( " + SSID + " )" + null */ + char mac[2 + 17 + 2 + 1]; /* "( " + MAC + " )" + null */ + char desc[sizeof ssid - 1 + 15 + 1]; /* room for channel/speed */ + double lat = 0, lon = 0; + waypoint *wpt_tmp; + int line_no = 0; + int stealth_num = 0, whitespace_num = 0; + long flags = 0; + int speed = 0, channel = 0; + struct tm tm; + + for(; fgets(ibuf, sizeof(ibuf), file_in);) { + char *field; + int field_num, len, i, stealth = 0; + + /* A sharp in column zero might be a comment. Or it might be + * something useful, like the date. + */ + + if (ibuf[0] == '#') { + if (strncmp(&ibuf[2], "$DateGMT:", 9) == 0) { + tm.tm_year = atoi(&ibuf[12]) - 1900; + tm.tm_mon = atoi(&ibuf[17]) - 1; + tm.tm_mday = atoi(&ibuf[20]); + } + + continue; + } + + field_num = 0; + line_no++; + field = csv_lineparse(ibuf, "\t", "", line_no); + + while (field) { + switch (field_num) { + case 0: /* lat */ + lat = atof(&field[2]); + if (field[0] == 'S') + lat = -lat; + break; + + case 1: /* long */ + lon = atof(&field[2]); + if (field[0] == 'W') + lon = -lon; + break; + + case 2: /* ( SSID ) */ + strcpy(ssid, &field[2]); /* zap "( " */ + len = strlen(ssid) - 2; + ssid[len] = 0; /* zap " )" */ + stealth = (len == 0); + /* don't alter SSID in snmac mode */ + if (!snmac) { + int found = 0; + /* check for all whitespace */ + for (i = 0; i < len && !found; i++) { + if (!isspace(ssid[i])) + found = 1; + } + + if (!stealth && !found) + snprintf(ssid, sizeof ssid, "Whitespace/%d", ++whitespace_num); + } + break; + + case 4: /* ( MAC address ) */ + strcpy(mac, &field[2]); /* zap "( " */ + mac[strlen(mac) - 2] = 0;/* zap " )" */ + break; + + case 5: /* time */ + tm.tm_hour = atoi(field); + tm.tm_min = atoi(&field[3]); + tm.tm_sec = atoi(&field[6]); + break; + + case 8: /* flags */ + flags = strtol(field, NULL, 16); + break; + + case 11: /* data rate */ + speed = atoi(field) / 10; + break; + + case 12: /* last channel */ + channel = atoi(field); + break; + + case 3: /* type */ + case 6: /* SNR/sig/noise */ + case 7: /* name */ + case 9: /* channel bits */ + case 10: /* beacon interval */ + default: + break; + } + + field_num++; + field = csv_lineparse(NULL, "\t", "", line_no); + } + + if (lat == 0 && lon == 0) /* skip records with no GPS data */ + continue; + + wpt_tmp = waypt_new(); + + if (stealth) { + if (!snmac) + snprintf(ssid, sizeof ssid, "Stealth/%d", ++stealth_num); + + if (flags & 0x0010) /* encrypted? */ + wpt_tmp->icon_descr = seicon; + else + wpt_tmp->icon_descr = sneicon; + } else { + if (flags & 0x0010) /* encrypted? */ + wpt_tmp->icon_descr = nseicon; + else + wpt_tmp->icon_descr = nsneicon; + } + + if (snmac) { + snprintf(desc, sizeof desc, "%s/%d Mbps/Ch %d", ssid, speed, channel); + wpt_tmp->shortname = xstrdup(mac); + } else { + snprintf(desc, sizeof desc, "%d Mbps/Ch %d/%s", speed, channel, mac); + wpt_tmp->shortname = xstrdup(ssid); + } + + wpt_tmp->description = xstrdup(desc); + wpt_tmp->longitude = lon; + wpt_tmp->latitude = lat; + wpt_tmp->creation_time = mktime(&tm); + + waypt_add(wpt_tmp); + } + + fix_netstumbler_dupes(); +} + +typedef struct +{ + unsigned long crc; + waypoint *wpt; +} htable_t; + +static +int +compare(const void *a, const void *b) +{ + unsigned long crc_a = ((const htable_t *)a)->crc; + unsigned long crc_b = ((const htable_t *)b)->crc; + + /* we can't just return crc_a - crc_b because the return type is + * signed. + * */ + + if (crc_a < crc_b) + return -1; + else if (crc_a > crc_b) + return 1; + else { + /* CRCs are equal; we need to subsort on the description (which + * includes the MAC address) to guarantee the same ordering of + * the output for any qsort() implementation. this is strictly + * to make the testo script happy. + * */ + + waypoint *wpt_a = ((const htable_t *)a)->wpt; + waypoint *wpt_b = ((const htable_t *)b)->wpt; + + return strcmp(wpt_a->description, wpt_b->description); + } +} + +/* netstumbler data will have a lot of duplicate shortnames if the SSID + * is used as the shortname (the default). salvage the dupes by + * synthesizing a (hopefully) unique shortname. + * */ + +static +void +fix_netstumbler_dupes(void) +{ + int i, ct = waypt_count(), serial = 0; + htable_t *htable, *bh; + queue *elem, *tmp; + extern queue waypt_head; + const char *snptr; + char *tmp_sn, *tmp_ptr; + unsigned long last_crc; + char ssid[32 + 5 + 1]; + + htable = (htable_t *) xmalloc(ct * sizeof *htable); + bh = htable; + + i = 0; + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + bh->wpt = (waypoint *) elem; + snptr = bh->wpt->shortname; + tmp_sn = xstrdup(snptr); + for (tmp_ptr = tmp_sn; *tmp_ptr; tmp_ptr++) + *tmp_ptr = tolower(*tmp_ptr); + bh->crc = get_crc32(tmp_sn, strlen(snptr)); + xfree(tmp_sn); + i ++; + bh ++; + } + + qsort(htable, ct, sizeof *htable, compare); + + last_crc = htable[0].crc + 1; /* force mismatch */ + + for (i = 0, bh = htable; i < ct; i++, bh++) { + if (last_crc == bh->crc) { + snprintf(ssid, sizeof ssid, "%s/%d", bh->wpt->shortname, ++serial); + xfree(bh->wpt->shortname); + bh->wpt->shortname = xstrdup(ssid); + } else + last_crc = bh->crc; + } + + xfree(htable); +} + +ff_vecs_t netstumbler_vecs = { + ff_type_file, + rd_init, + NULL, + rd_deinit, + NULL, + data_read, + NULL, + NULL, + netstumbler_args +}; diff --git a/nmea.c b/nmea.c new file mode 100644 index 000000000..3b0f136ae --- /dev/null +++ b/nmea.c @@ -0,0 +1,457 @@ +/* + Read files containing selected NMEA 0183 sentences. + Based on information by Eino Uikkanenj + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include + +#include "defs.h" + +/********************************************************** + + ' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + ' $GPGGA - Global Positioning System Fix Data + ' $GPGGA,155537,6006.718,N,02426.290,E,1,05,2.4,50.5,M,19.7,M,,*79 + ' 2 123519 Fix taken at 12:35:19 UTC + ' 3,4 4807.038,N Latitude 48 deg 07.038' N + ' 5,6 01131.324,E Longitude 11 deg 31.324' E + ' 7 1 Fix quality: 0 = invalid + ' 1 = GPS fix + ' 2 = DGPS fix + ' 8 08 Number of satellites being tracked + ' 9 0.9 Horizontal dilution of position + ' 10,11 545.4,M Altitude, Metres, above mean sea level + ' 12,13 46.9,M Height of geoid (mean sea level) above WGS84 ellipsoid + ' 14 (empty field) time in seconds since last DGPS update + ' 15 (empty field) DGPS station ID number + + ' $GPWPL - waypoint location + ' $GPWPL,4917.16,N,12310.64,W,003*65 + ' 2,3 4917.16,N Latitude of waypoint + ' 4,5 12310.64,W Longitude of waypoint + ' 6 003 Waypoint ID + + ' $GPGLL - Geographic position, Latitude and Longitude + ' $GPGLL,4916.45,N,12311.12,W,225444,A + ' 2,3 4916.46,N Latitude 49 deg. 16.45 min. North + ' 4,5 12311.12,W Longitude 123 deg. 11.12 min. West + ' 6 225444 Fix taken at 22:54:44 UTC + ' 7 A Data valid + + ' $GPRMC - Recommended minimum specific GNSS Data + ' $GPRMC,085721.194,A,5917.7210,N,01103.9227,E,21.42,50.33,300504,,*07 + ' 2 085721 Fix taken at 08:57:21 UTC + ' 3 A Fix valid (this field reads V if fix is not valid) + ' 4,5 5917.7210,N Latitude 59 deg 17.7210' N + ' 6,7 01103.9227,E Longitude 11 deg 03.9227' E + ' 8 21.42 Speed over ground (knots) + ' 9 50.33 Course over ground (true) + ' 10 300504 Date 30/05-2004 + ' 11 Empty field Magnetic variation + + + ' The optional checksum field consists of a "*" and two hex digits repre- + ' senting the exclusive OR of all characters between, but not including, + ' the "$" and "*". A checksum is required on some sentences. + +****************************************/ + +/* + * An input file may have both GGA and GLL and RMC sentences for the exact + * same position fix. If we see a single GGA, start ignoring GLL's and RMC's. + * GLL's will also be ignored if RMC's are found and GGA's not found. + */ + +typedef enum { + gp_unknown = 0, + gpgga, + gplgll, + gprmc +} preferred_posn_type; + +static FILE *file_in; +static FILE *file_out; +static route_head *trk_head; +static void *mkshort_handle; +static preferred_posn_type posn_type; +static time_t creation_time; + +#define MYNAME "nmea" + +/* + * Slightly different than the Magellan checksum fn. + */ +static int +nmea_cksum(const char *const buf) +{ + int x = 0 ; + const char *p; + + for (p = buf; *p; p++) { + x ^= *p; + } + return x; +} + +static void +nmea_rd_init(const char *fname) +{ + file_in = xfopen(fname, "r", MYNAME); +} + +static void +nmea_rd_deinit(void) +{ + fclose(file_in); +} + +static void +nmea_wr_init(const char *portname) +{ + file_out = xfopen(portname, "w+", MYNAME); + + mkshort_handle = mkshort_new_handle(); + setshort_length(mkshort_handle, 6); +} + +static void +nmea_wr_deinit(void) +{ + fclose(file_out); +} + +void +gpgll_parse(char *ibuf) +{ + double latdeg, lngdeg; + char lngdir, latdir; + int hms; + char valid; + struct tm tm; + waypoint *waypt; + + if (trk_head == NULL) { + trk_head = route_head_alloc(); + track_add_head(trk_head); + } + + memset(&tm, 0, sizeof(tm)); + + sscanf(ibuf,"$GPGLL,%lf,%c,%lf,%c,%d,%c,", + &latdeg,&latdir, + &lngdeg,&lngdir, + &hms,&valid); + + if (valid != 'A') + return; + tm.tm_sec = hms % 100; + hms = hms / 100; + tm.tm_min = hms % 100; + hms = hms / 100; + tm.tm_hour = hms % 100; + + waypt = waypt_new(); + + waypt->creation_time = creation_time; + + if (latdir == 'S') latdeg = -latdeg; + waypt->latitude = ddmm2degrees(latdeg); + + if (lngdir == 'W') lngdeg = -lngdeg; + waypt->longitude = ddmm2degrees(lngdeg); + + route_add_wpt(trk_head, waypt); +} + +static void +gpgga_parse(char *ibuf) +{ + double latdeg, lngdeg; + char lngdir, latdir; + double hms; + int fix; + int nsats; + double hdop; + struct tm tm; + double alt; + char altunits; + waypoint *waypt; + + if (trk_head == NULL) { + trk_head = route_head_alloc(); + track_add_head(trk_head); + } + + memset(&tm, 0, sizeof(tm)); + + sscanf(ibuf,"$GPGGA,%lf,%lf,%c,%lf,%c,%d,%d,%lf,%lf,%c", + &hms, &latdeg,&latdir, + &lngdeg,&lngdir, + &fix,&nsats,&hdop,&alt,&altunits); + + if (fix == 0) + return; + + tm.tm_sec = (long) hms % 100; + hms = hms / 100; + tm.tm_min = (long) hms % 100; + hms = hms / 100; + tm.tm_hour = (long) hms % 100; + + waypt = waypt_new(); + + waypt->creation_time = creation_time; + + if (latdir == 'S') latdeg = -latdeg; + waypt->latitude = ddmm2degrees(latdeg); + + if (lngdir == 'W') lngdeg = -lngdeg; + waypt->longitude = ddmm2degrees(lngdeg); + + waypt->altitude = alt; + route_add_wpt(trk_head, waypt); + +} + +static void +gprmc_parse(char *ibuf) +{ + double latdeg, lngdeg; + char lngdir, latdir; + double hms; + double speed, course; + char fix; + unsigned int dmy; + struct tm tm; + waypoint *waypt; + + if (trk_head == NULL) { + trk_head = route_head_alloc(); + track_add_head(trk_head); + } + + memset(&tm, 0, sizeof(tm)); + + sscanf(ibuf,"$GPRMC,%lf,%c,%lf,%c,%lf,%c,%lf,%lf,%u", + &hms, &fix, &latdeg, &latdir, + &lngdeg, &lngdir, + &speed, &course, &dmy); + + if (fix != 'A') + return; + tm.tm_sec = (long) hms % 100; + hms = hms / 100; + tm.tm_min = (long) hms % 100; + hms = hms / 100; + tm.tm_hour = (long) hms % 100; + + tm.tm_year = dmy % 100 + 100; + dmy = dmy / 100; + tm.tm_mon = dmy % 100 - 1; + dmy = dmy / 100; + tm.tm_mday = dmy; + creation_time = mktime(&tm) + get_tz_offset(); + + if (posn_type == gpgga) + return; + + waypt = waypt_new(); + waypt->creation_time = creation_time; + + if (latdir == 'S') latdeg = -latdeg; + waypt->latitude = ddmm2degrees(latdeg); + + if (lngdir == 'W') lngdeg = -lngdeg; + waypt->longitude = ddmm2degrees(lngdeg); + + route_add_wpt(trk_head, waypt); +} + +static void +gpwpl_parse(char *ibuf) +{ + waypoint *waypt; + double latdeg, lngdeg; + char latdir, lngdir; + char sname[7]; + + sscanf(ibuf,"$GPWPL,%lf,%c,%lf,%c,%[^*]", + &latdeg,&latdir, + &lngdeg,&lngdir, + &sname); + + waypt = waypt_new(); + + if (latdir == 'S') latdeg = -latdeg; + waypt->latitude = ddmm2degrees(latdeg); + if (lngdir == 'W') lngdeg = -lngdeg; + waypt->longitude = ddmm2degrees(lngdeg); + + waypt->shortname = xstrdup(sname); + + waypt_add(waypt); + +} + +static void +gpzda_parse(char *ibuf) +{ + double hms; + int dd, mm, yy, lclhrs, lclmins; + struct tm tm; + + memset(&tm, 0, sizeof(tm)); + sscanf(ibuf,"$GPZDA,%lf,%d,%d,%d,%d,%d", + &hms, &dd, &mm, &yy, &lclhrs, &lclmins); + tm.tm_sec = (int) hms % 100; + tm.tm_min = (((int) hms - tm.tm_sec) / 100) % 100; + tm.tm_hour = (int) hms / 10000; + tm.tm_mday = dd; + tm.tm_mon = mm - 1; + tm.tm_year = yy - 1900; + creation_time = mktime(&tm) + get_tz_offset(); +} + +static void +nmea_read(void) +{ + char ibuf[1024]; + char *ck; + int ckval, ckcmp; + struct tm tm; + + creation_time = mktime(&tm) + get_tz_offset() + current_time(); + + while (fgets(ibuf, sizeof(ibuf), file_in)) { + ck = strrchr(ibuf, '*'); + if (ck != NULL) { + *ck = '\0'; + ckval = nmea_cksum(&ibuf[1]); + *ck = '*'; + ck++; + sscanf(ck, "%2X", &ckcmp); + if (ckval != ckcmp) { +#if 0 + printf("ckval %X, %X, %s\n", ckval, ckcmp, ck); + printf("NMEA %s\n", ibuf); +#endif + continue; + } + } + if (0 == strncmp(ibuf, "$GPWPL,", 7)) { + gpwpl_parse(ibuf); + } else + if (0 == strncmp(ibuf, "$GPGGA,", 7)) { + posn_type = gpgga; + gpgga_parse(ibuf); + } else + if (0 == strncmp(ibuf, "$GPRMC,", 7)) { + if (posn_type != gpgga) { + posn_type = gprmc; + } + /* + * Allways call gprmc_parse() because like GPZDA + * it contains the full date. + */ + gprmc_parse(ibuf); + } else + if (0 == strncmp(ibuf, "$GPGLL,", 7)) { + if ((posn_type != gpgga) && (posn_type != gprmc)) { + gpgll_parse(ibuf); + } + } else + if (0 == strncmp(ibuf, "$GPZDA,",7)) { + gpzda_parse(ibuf); + } + } +} + +static void +nmea_wayptpr(const waypoint *wpt) +{ + char obuf[200]; + double lat,lon; + char *s; + int cksum; + + lat = degrees2ddmm(wpt->latitude); + lon = degrees2ddmm(wpt->longitude); + s = mkshort(mkshort_handle, wpt->shortname); + + snprintf(obuf, sizeof(obuf), "GPWPL,%08.3f,%c,%09.3f,%c,%s", + fabs(lat), lat < 0 ? 'S' : 'N', + fabs(lon), lon < 0 ? 'W' : 'E', s + + ); + cksum = nmea_cksum(obuf); + fprintf(file_out, "$%s*%02X\n", obuf, cksum); + + xfree(s); + +} + +void +nmea_trackpt_pr(const waypoint *wpt) +{ + char obuf[200]; + double lat,lon; + int cksum; + struct tm *tm; + int hms; + + lat = degrees2ddmm(wpt->latitude); + lon = degrees2ddmm(wpt->longitude); + + tm = gmtime(&wpt->creation_time); + if ( tm ) { + hms = tm->tm_hour * 10000 + tm->tm_min * 100 + + tm->tm_sec; + } else { + hms = 0; + } + + snprintf(obuf, sizeof(obuf), "GPGGA,%06d,%08.3f,%c,%09.3f,%c,04,0,0,%.3f,M,0.0,M,,", + hms, + fabs(lat), lat < 0 ? 'S' : 'N', + fabs(lon), lon < 0 ? 'W' : 'E', + wpt->altitude == unknown_alt ? 0 : wpt->altitude); + + cksum = nmea_cksum(obuf); + fprintf(file_out, "$%s*%02X\n", obuf, cksum); +} + +static void +nmea_write() +{ + waypt_disp_all(nmea_wayptpr); + track_disp_all(NULL, NULL, nmea_trackpt_pr); +} + +ff_vecs_t nmea_vecs = { + ff_type_file, + nmea_rd_init, + nmea_wr_init, + nmea_rd_deinit, + nmea_wr_deinit, + nmea_read, + nmea_write, + NULL +}; diff --git a/ozi.c b/ozi.c new file mode 100644 index 000000000..ff9487571 --- /dev/null +++ b/ozi.c @@ -0,0 +1,703 @@ +/* + OziExplorer Waypoints/Tracks/Routes + Comma Delimited + + As described in OziExplorer Help File + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "csv_util.h" +#include +#include /* for floor */ + +#define MYNAME "OZI" + + +static FILE *file_in; +static FILE *file_out; +static void *mkshort_handle; +static route_head *trk_head; +static route_head *rte_head; + +static int track_out_count; +static int route_out_count; +static int route_wpt_count; + +static char *snlenopt = NULL; +static char *snwhiteopt = NULL; +static char *snupperopt = NULL; +static char *snuniqueopt = NULL; + +static +arglist_t ozi_args[] = { + {"snlen", &snlenopt, "Max synthesized shortname length", + NULL, ARGTYPE_INT}, + {"snwhite", &snwhiteopt, "(0/1) Allow whitespace synth. shortnames", + NULL, ARGTYPE_BOOL}, + {"snupper", &snupperopt, "(0/1) UPPERCASE synth. shortnames", + NULL, ARGTYPE_BOOL}, + {"snunique", &snuniqueopt, "(0/1) Make synth. shortnames unique", + NULL, ARGTYPE_BOOL}, + {0, 0, 0, 0, 0} +}; + +gpsdata_type ozi_objective; + +static char *ozi_ofname = NULL; + +static void +ozi_openfile(char *fname) { + char *c, *tmpname; + char *ozi_extensions[] = {0, "plt", "wpt", "rte"}; + char buff[32]; + + /* if we're doing multi-track output, sequence the filenames like: + * mytrack.plt, mytrack-1.plt... + */ + + if ((track_out_count) && (ozi_objective == trkdata)) { + sprintf(buff, "-%d", track_out_count); + } else { + buff[0] = '\0'; + } + + /* allocate more than enough room for new filename */ + tmpname = (char *) xcalloc(1, strlen(fname) + + strlen(buff) + + strlen(ozi_extensions[ozi_objective]) + + 2); /* . (dot) plus null term */ + + strcpy(tmpname, fname); + + /* locate and remove file extension */ + c = strrchr(tmpname, '.'); + + if (c) + *c = '\0'; + + /* append the -xx sequence number for tracks if needed */ + strcat(tmpname + strlen(tmpname), buff); + + strcat(tmpname, "."); + + /* append the extension after the "." */ + strcat(tmpname, ozi_extensions[ozi_objective]); + + /* re-open file_out with the new filename */ + if (file_out) { + fclose(file_out); + file_out = NULL; + } + + file_out = xfopen(tmpname, "wb", MYNAME); + + xfree(tmpname); + + return; +} + +static void +ozi_track_hdr(const route_head * rte) +{ + static char *ozi_trk_header = + "OziExplorer Track Point File Version 2.1\r\n" + "WGS 84\r\n" + "Altitude is in Feet\r\n" + "Reserved 3\r\n" + "0,2,255,ComplimentsOfGPSBabel,0,0,2,8421376\r\n" + "0\r\n"; + + ozi_openfile(ozi_ofname); + fprintf(file_out, ozi_trk_header); + + track_out_count++; +} + +static void +ozi_track_disp(const waypoint * waypointp) +{ + double alt_feet; + double ozi_time; + + ozi_time = (waypointp->creation_time / 86400.0) + 25569.0; + + if (waypointp->altitude == unknown_alt) { + alt_feet = -777; + } else { + alt_feet = (waypointp->altitude * 3.2808); + } + + fprintf(file_out, "%.6f,%.6f,0,%.0f,%.5f,,\r\n", + waypointp->latitude, waypointp->longitude, alt_feet, ozi_time); +} + +static void +ozi_track_tlr(const route_head * rte) +{ +} + +static void +ozi_track_pr() +{ + track_disp_all(ozi_track_hdr, ozi_track_tlr, ozi_track_disp); +} + +static void +ozi_route_hdr(const route_head * rte) +{ + static char *ozi_route_header = + "OziExplorer Route File Version 1.0\r\n" + "WGS 84\r\n" + "Reserved 1\r\n" + "Reserved 2\r\n"; + + /* prologue on 1st pass only */ + if (route_out_count == 0) { + fprintf(file_out, ozi_route_header); + } + + route_out_count++; + route_wpt_count = 0; + + /* + * Route Record + * Field 1 : R - indicating route details + * Field 2 : Number - this is the location in the array, must be unique, usually start at 0 for Garmins 1 for other and increment. + * Field 3 : Name - the waypoint name, use the correct length name to suit the GPS type. + * Field 4 : Description. + * Field 5 : Route Color as displayed on map (RGB). + * + * R, 0,R0 ,,255 + * R, 1, ICP GALHETA,, 16711680 + */ + + fprintf(file_out, "R,%d,%s,%s,\r\n", + route_out_count, + rte->rte_name ? rte->rte_name : "", + rte->rte_desc ? rte->rte_desc : ""); + +} + +static void +ozi_route_disp(const waypoint * waypointp) +{ + double alt_feet; + double ozi_time; + + route_wpt_count++; + + ozi_time = (waypointp->creation_time / 86400.0) + 25569.0; + + if (waypointp->altitude == unknown_alt) { + alt_feet = -777; + } else { + alt_feet = (waypointp->altitude * 3.2808); + } + +/* + * Field 1 : W - indicating route waypoint details. + * Field 2 : Route Number - location in array of routes + * Field 3 : Number - this is the location in the array of route waypoints, this field is now ignored. + * Field 4 : Wp Number - this is the number of the waypoint (the Wp number within the GPS for lowrances) + * Field 5 : Name - the waypoint name, use the correct length name to suit the GPS type. + * Field 6 : Latitude - decimal degrees. + * Field 7 : Longitude - decimal degrees. + * Field 8 : Date - see Date Format below, if blank a preset date will be used + * Field 9 : Symbol - 0 to number of symbols in GPS + * Field 10 : Status - always set to 1 + * Field 11 : Map Display Format + * Field 12 : Foreground Color (RGB value) + * Field 13 : Background Color (RGB value) + * Field 14 : Description (max 40), no commas + * Field 15 : Pointer Direction + * Field 16 : Garmin Display Format + * + * W,1,7,7,007,-25.581670,-48.316660,36564.54196,10,1,4,0,65535,TR ILHA GALHETA,0,0 + */ + + fprintf(file_out, "W,%d,%d,,%s,%.6f,%.6f,%.5f,0,1,3,0,65535,%s,0,0\r\n", + route_out_count, + route_wpt_count, + waypointp->shortname ? waypointp->shortname : "", + waypointp->latitude, + waypointp->longitude, + ozi_time, + waypointp->description ? waypointp->description : ""); + +} + +static void +ozi_route_tlr(const route_head * rte) +{ +} + +static void +ozi_route_pr() +{ + route_disp_all(ozi_route_hdr, ozi_route_tlr, ozi_route_disp); +} + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "r", MYNAME); + + mkshort_handle = mkshort_new_handle(); +} + +static void +rd_deinit(void) +{ + fclose(file_in); + file_in = NULL; + mkshort_del_handle(mkshort_handle); +} + +static void +wr_init(const char *fname) +{ + + /* At this point, we have no idea whether we'll be writing waypoint, + * route, or tracks. So we'll hold off opening any files until + * we're actually ready to write. + */ + + ozi_ofname = (char *)fname; + + mkshort_handle = mkshort_new_handle(); + + /* set mkshort options from the command line if applicable */ + if (global_opts.synthesize_shortnames) { + + if (snlenopt) + setshort_length(mkshort_handle, atoi(snlenopt)); + else + setshort_length(mkshort_handle, 32); + + if (snwhiteopt) + setshort_whitespace_ok(mkshort_handle, atoi(snwhiteopt)); + + if (snupperopt) + setshort_mustupper(mkshort_handle, atoi(snupperopt)); + + if (snuniqueopt) + setshort_mustuniq(mkshort_handle, atoi(snuniqueopt)); + + setshort_badchars(mkshort_handle, "\","); + } + +} + +static void +wr_deinit(void) +{ + fclose(file_out); + file_out = NULL; + ozi_ofname = NULL; + + mkshort_del_handle(mkshort_handle); +} + +static void +ozi_parse_waypt(int field, char *str, waypoint * wpt_tmp) +{ + double alt; + + switch (field) { + case 0: + /* sequence # */ + break; + case 1: + /* waypoint name */ + wpt_tmp->shortname = csv_stringtrim(str, "", 0); + break; + case 2: + /* degrees latitude */ + wpt_tmp->latitude = atof(str); + break; + case 3: + /* degrees longitude */ + wpt_tmp->longitude = atof(str); + break; + case 4: + /* DAYS since 1900 00:00:00 in days.days (5.5) */ + wpt_tmp->creation_time = (atof(str) - 25569.0) * 86400.0; + break; + case 5: + /* icons 0-xx */ + break; + case 6: + /* unknown - always 1 */ + break; + case 7: + /* display format options 0-8 */ + break; + case 8: + /* foreground color (0=black) */ + break; + case 9: + /* background color (65535=yellow) */ + break; + case 10: + /* Description */ + wpt_tmp->description = csv_stringtrim(str, "", 0); + break; + case 11: + /* pointer direction 0,1,2,3 bottom,top,left,right */ + break; + case 12: + /* garmin gps display flags (0-name w/sym, 1-sym only, 2-comment w/symbol */ + break; + case 13: + /* proximity distance - meters */ + break; + case 14: + /* altitude in feet */ + alt = atof(str); + if (alt == -777) { + wpt_tmp->altitude = unknown_alt; + } else { + wpt_tmp->altitude = alt * .3048; + } + break; + case 15: + /* waypoint text name size */ + break; + case 16: + /* bold checkbox (1=bold, default 0) */ + break; + case 17: + /* symbol size - 17 default */ + break; + /* + * Fields 18-23 were added around version 3.90.4g of + * Ozi, but aren't documented. We silently ignore + * these or any additional fields we don't need. + */ + default: + break; + } +} + +static void +ozi_parse_track(int field, char *str, waypoint * wpt_tmp) +{ + double alt; + + switch (field) { + case 0: + /* latitude */ + wpt_tmp->latitude = atof(str); + break; + case 1: + /* longitude */ + wpt_tmp->longitude = atof(str); + break; + case 2: + /* ignore */ + break; + case 3: + /* altitude in feet */ + alt = atof(str); + if (alt == -777) { + wpt_tmp->altitude = unknown_alt; + } else { + wpt_tmp->altitude = alt * .3048; + } + break; + case 4: + /* DAYS since 1900 00:00:00 in days.days (5.5) */ + wpt_tmp->creation_time = (atof(str) - 25569.0) * 86400.0; + break; + default: + break; + } +} + +static void +ozi_parse_routepoint(int field, char *str, waypoint * wpt_tmp) +{ + + switch (field) { + case 0: + /* W */ + break; + case 1: + /* route # */ + break; + case 2: + /* waypoint # -- ignored by ozi */ + break; + case 3: + /* waypoint # */ + break; + case 4: + /* waypoint name */ + wpt_tmp->shortname = csv_stringclean(str, ","); + break; + case 5: + /* latitude */ + wpt_tmp->latitude = atof(str); + break; + case 6: + /* longitude */ + wpt_tmp->longitude = atof(str); + break; + case 7: + /* DAYS since 1900 00:00:00 in days.days (5.5) */ + wpt_tmp->creation_time = (atof(str) - 25569.0) * 86400.0; + break; + case 8: + /* symbol */ + break; + case 9: + /* status */ + break; + case 10: + /* map display format */ + break; + case 11: + /* foreground color (RGB) */ + break; + case 12: + /* background color (RGB) */ + break; + case 13: + /* description */ + wpt_tmp->description = csv_stringclean(str, ","); + break; + default: + break; + } +} + +static void +ozi_parse_routeheader(int field, char *str, waypoint * wpt_tmp) +{ + + switch (field) { + case 0: + /* R */ + rte_head = route_head_alloc(); + route_add_head(rte_head); + break; + case 1: + /* route # */ + rte_head->rte_num = atoi(str); + break; + case 2: + /* route name */ + rte_head->rte_name = csv_stringclean(str, ","); + break; + case 3: + /* route description */ + rte_head->rte_desc = csv_stringclean(str, ","); + break; + case 4: + /* route color */ + break; + default: + break; + } +} + +static void +data_read(void) +{ + char buff[1024]; + char *s; + waypoint *wpt_tmp; + int i; + int linecount = 0; + + do { + linecount++; + memset(buff, '\0', sizeof(buff)); + fgets(buff, sizeof(buff), file_in); + + /* + * this is particularly nasty. use the first line of the file + * to attempt to divine the data type we are parsing + */ + if (linecount == 1) { + if (strstr(buff, "Track Point") != NULL) { + trk_head = route_head_alloc(); + track_add_head(trk_head); + ozi_objective = trkdata; + } else + if (strstr(buff, "Route File") != NULL) { + ozi_objective = rtedata; + } else { + ozi_objective = wptdata; + } + } + if ((strlen(buff)) && (strstr(buff, ",") != NULL)) { + + wpt_tmp = waypt_new(); + + /* data delimited by commas, possibly enclosed in quotes. */ + s = buff; + s = csv_lineparse(s, ",", "", linecount); + + i = 0; + while (s) { + switch (ozi_objective) { + case trkdata: + ozi_parse_track(i, s, wpt_tmp); + break; + case rtedata: + if (buff[0] == 'R') { + ozi_parse_routeheader(i, s, wpt_tmp); + } else { + ozi_parse_routepoint(i, s, wpt_tmp); + } + + break; + case wptdata: + ozi_parse_waypt(i, s, wpt_tmp); + break; + } + i++; + s = csv_lineparse(NULL, ",", "", linecount); + } + + switch (ozi_objective) { + case trkdata: + if (linecount > 6) /* skipping over file header */ + route_add_wpt(trk_head, wpt_tmp); + else + waypt_free(wpt_tmp); + break; + case rtedata: + if (linecount > 5) /* skipping over file header */ + route_add_wpt(rte_head, wpt_tmp); + else + waypt_free(wpt_tmp); + break; + case wptdata: + if (linecount > 4) /* skipping over file header */ + waypt_add(wpt_tmp); + else + waypt_free(wpt_tmp); + break; + } + + } else { + /* empty line */ + } + + } while (!feof(file_in)); +} + +static void +ozi_waypt_pr(const waypoint * wpt) +{ + static int index = 0; + double alt_feet; + double ozi_time; + char *description; + char *shortname; + + ozi_time = (wpt->creation_time / 86400.0) + 25569.0; + + if (wpt->altitude == unknown_alt) { + alt_feet = -777; + } else { + alt_feet = (wpt->altitude * 3.2808); + } + + if ((!wpt->shortname) || (global_opts.synthesize_shortnames)) { + if (wpt->description) { + if (global_opts.synthesize_shortnames) + shortname = mkshort(mkshort_handle, wpt->description); + else + shortname = csv_stringclean(wpt->description, ","); + } else { + /* no description available */ + shortname = xstrdup(""); + } + } else { + shortname = csv_stringclean(wpt->shortname, ","); + } + + if (!wpt->description) { + if (shortname) { + description = csv_stringclean(shortname, ","); + } else { + description = xstrdup(""); + } + } else { + description = csv_stringclean(wpt->description, ","); + } + + index++; + + fprintf(file_out, + "%d,%s,%.6f,%.6f,%.5f,%d,%d,%d,%d,%d,%s,%d,%d,%d,%.0f,%d,%d,%d\r\n", + index, shortname, wpt->latitude, wpt->longitude, ozi_time, 0, + 1, 3, 0, 65535, description, 0, 0, 0, alt_feet, 6, 0, 17); + + xfree(description); + xfree(shortname); + +} + +static void +data_write(void) +{ + static char *ozi_wpt_header = + "OziExplorer Waypoint File Version 1.1\r\n" + "WGS 84\r\n" + "Reserved 2\r\n" + "Reserved 3\r\n"; + + track_out_count = route_out_count = 0; + + if (waypt_count()) { + ozi_objective = wptdata; + ozi_openfile(ozi_ofname); + fprintf(file_out, ozi_wpt_header); + waypt_disp_all(ozi_waypt_pr); + } + + if (track_count()) { + ozi_objective = trkdata; + ozi_track_pr(); /* ozi_track_hdr handles filenames / file_out */ + } + + if (route_count()) { + ozi_objective = rtedata; + ozi_openfile(ozi_ofname); /* ozi routes go in one big file */ + ozi_route_pr(); + } + +} + +ff_vecs_t ozi_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL, + ozi_args +}; diff --git a/palmdoc.c b/palmdoc.c new file mode 100644 index 000000000..40cf79b00 --- /dev/null +++ b/palmdoc.c @@ -0,0 +1,617 @@ +/* + Output only format for PalmDoc + + Copyright (C) 2004 Scott Brynen, scott (at) brynen.com + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + Copyright (C) 2004 Ronald L. Parker, ron@parkrrrr.com + Portions from txt2pdbdoc, Copyright (C) 1998 Paul J. Lucas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA +*/ + + +#include "defs.h" +#include "jeeps/gpsmath.h" +#include +#include "coldsync/palm.h" +#include "coldsync/pdb.h" + +static FILE *file_out; +static void *mkshort_handle; +static void *mkshort_bookmark_handle; +static const char *out_fname; +static struct pdb *opdb; +static struct pdb_record *opdb_rec; + +static char *suppresssep = NULL; +static char *dbname = NULL; +static char *bmid = NULL; +static char *includelogs = NULL; + +static int ct = 1; +static int offset = 0; + +static char *encrypt; + +#define MYNAME "PALMDOC" + +/* constants */ +#define BUFFER_SIZE 4096 /* big enough for uncompressed record */ +#define COMPRESSED 2 +#define COUNT_BITS 3 /* why this value? I don't know */ +#define DISP_BITS 11 /* ditto */ + +#define DOC_CREATOR 0x52454164 /* "REAd" */ +#define DOC_TYPE 0x54455874 /* "TEXt" */ +#define UNCOMPRESSED 1 + +struct buffer { + unsigned char *data; + unsigned len; +}; + +#define NEW_BUFFER(b) (b)->data = (unsigned char *)xmalloc( ((b)->len = 0,BUFFER_SIZE) ) + +static +arglist_t palmdoc_args[] = { + { "nosep", &suppresssep, + "Suppress separator lines between waypoints", NULL, + ARGTYPE_BOOL }, + {"dbname", &dbname, "Database name", NULL, ARGTYPE_STRING }, + {"encrypt", &encrypt, "Encrypt hints with ROT13", NULL, + ARGTYPE_BOOL }, + { "logs", &includelogs, + "Include groundspeak logs if present", NULL, ARGTYPE_BOOL }, + { "bookmarks_short", &bmid, "Include short name in bookmarks", + NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + +static struct buffer buf; + +struct doc_record0 /* 16 bytes total */ +{ + unsigned short version; /* 1 = plain text, 2 = compressed */ + unsigned short reserved1; + unsigned long doc_size; /* in bytes, when uncompressed */ + unsigned short num_records; /* PDB header numRecords - 1 */ + unsigned short rec_size; /* usually RECORD_SIZE_MAX */ + unsigned long reserved2; + unsigned short recsizes[1]; +}; + +static struct recordsize { + int size; + struct recordsize *next; +} *recordsize_tail; + +static struct bookmark { + int offset; + char *text; + struct bookmark *next; +} *bookmark_tail; + +struct bookmark_record { + char text[16]; + unsigned long offset; +}; + +static void put_byte(struct buffer *b, unsigned char c, int *space) +{ + if ( *space ) { + *space = 0; + /* + ** There is an outstanding space char: see if we can squeeze it + ** in with an ASCII char. + */ + if ( c >= 0x40 && c <= 0x7F ) { + b->data[ b->len++ ] = c ^ 0x80; + return; + } + b->data[ b->len++ ] = ' '; /* couldn't squeeze it in */ + } else if ( c == ' ' ) { + *space = 1; + return; + } + + if ( (c >= 1 && c <= 8) || c >= 0x80 ) + b->data[ b->len++ ] = '\1'; + + b->data[ b->len++ ] = c; +} + +static unsigned char * mem_find(unsigned char *t, int t_len, unsigned char *m, int m_len) +{ + register int i; + for ( i = t_len - m_len + 1; i > 0; --i, ++t ) + if ( *t == *m && !memcmp( t, m, m_len ) ) + return t; + return 0; +} + + +static void compress( struct buffer *b ) +{ + + unsigned i, j; + int space = 0; + + unsigned char *buf_orig; + unsigned char *p; /* walking test hit; works up on successive matches */ + unsigned char *p_prev; + unsigned char *head; /* current test string */ + unsigned char *tail; /* 1 past the current test buffer */ + unsigned char *end; /* 1 past the end of the input buffer */ + + p = p_prev = head = buf_orig = b->data; + tail = head + 1; + end = b->data + b->len; + + NEW_BUFFER( b ); + b->len = 0; + + /* loop, absorbing one more char from the input buffer on each pass */ + while ( head != end ) { + /* establish where the scan can begin */ + if ( head - p_prev > (( 1 << DISP_BITS )-1) ) + p_prev = head - (( 1 << DISP_BITS )-1); + + /* scan in the previous data for a match */ + p = mem_find( p_prev, tail - p_prev, head, tail - head ); + + /* on a mismatch or end of buffer, issued codes */ + if ( !p || p == head || tail - head > ( 1 << COUNT_BITS ) + 2 + || tail == end + ) { + /* issued the codes */ + /* first, check for short runs */ + if ( tail - head < 4 ) { + put_byte( b, *head++, &space ); + } + else { + unsigned dist = head - p_prev; + unsigned compound = (dist << COUNT_BITS) + + tail - head - 4; + + /* for longer runs, issue a run-code */ + /* issue space char if required */ + if ( space ) { + b->data[ b->len++ ] = ' '; + space = 0; + } + + b->data[ b->len++ ] = 0x80 + ( compound >> 8 ); + b->data[ b->len++ ] = compound & 0xFF; + head = tail - 1;/* and start again */ + } + p_prev = buf_orig; /* start search again */ + } else + p_prev = p; /* got a match */ + + /* when we get to the end of the buffer, don't inc past the */ + /* end; this forces the residue chars out one at a time */ + if ( tail != end ) + ++tail; + } + xfree( buf_orig ); + + if ( space ) + b->data[ b->len++ ] = ' '; /* add left-over space */ + + /* final scan to merge consecutive high chars together */ + for ( i = j = 0; i < b->len; ++i, ++j ) { + b->data[ j ] = b->data[ i ]; + + /* skip run-length codes */ + if ( b->data[ j ] >= 0x80 && b->data[ j ] < 0xC0 ) + b->data[ ++j ] = b->data[ ++i ]; + + /* if we hit a high char marker, look ahead for another */ + else if ( b->data[ j ] == '\1' ) { + b->data[ j + 1 ] = b->data[ i + 1 ]; + while ( i + 2 < b->len && + b->data[ i + 2 ] == 1 && b->data[ j ] < 8 + ) { + b->data[ j ]++; + b->data[ j + b->data[ j ] ] = b->data[ i + 3 ]; + i += 2; + } + j += b->data[ j ]; + ++i; + } + } + b->len = j; +} + +static void write_header( void ) { + + int recs = ct-1; + struct doc_record0 *rec0; + --ct; + + rec0 = xcalloc( 1, sizeof(struct doc_record0)+(ct-1)*sizeof(short)); + be_write16( &rec0->version, COMPRESSED ); + be_write16( &rec0->reserved1, 0 ); + be_write32( &rec0->doc_size, offset ); + be_write16( &rec0->num_records, ct ); + be_write16( &rec0->rec_size, 4096 ); + be_write32( &rec0->reserved2, 0 ); + while ( recs ) { + struct recordsize *oldrec = recordsize_tail; + be_write16( &rec0->recsizes[recs], oldrec->size ); + recordsize_tail = oldrec->next; + xfree( oldrec ); + --recs; + } + + opdb_rec = new_Record (0, 0, 0, sizeof(struct doc_record0)+sizeof(short)*(ct-1), (const ubyte *)rec0); + + if (opdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create summary record\n"); + } + + if (pdb_InsertRecord(opdb, NULL, opdb_rec)) { + fatal(MYNAME ": libpdb couldn't insert summary record\n"); + } +} + +static void write_bookmarks( void ) { + struct bookmark *oldmark = NULL; + struct bookmark_record rec; + + struct bookmark *newtail = NULL; + + /* reverse the bookmark list */ + while ( bookmark_tail ) { + oldmark = bookmark_tail; + bookmark_tail = oldmark->next; + oldmark->next = newtail; + newtail = oldmark; + } + bookmark_tail = newtail; + + ct++; + while ( bookmark_tail ) { + oldmark = bookmark_tail; + bookmark_tail = oldmark->next; + + be_write32( &rec.offset, oldmark->offset ); + memset( rec.text, 16, 0 ); + strncpy( rec.text, oldmark->text, 16 ); + + opdb_rec = new_Record( 0, 0, ct++, + sizeof(struct bookmark_record), + (const ubyte *)&rec ); + if (opdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create bookmark record\n"); + } + + if (pdb_AppendRecord(opdb, opdb_rec)) { + fatal(MYNAME ": libpdb couldn't append bookmark record\n"); + } + + + xfree( oldmark ); + } +} + +static void commit_buffer( void ) { + + struct recordsize *newrec = xcalloc( 1, sizeof(struct recordsize)); + newrec->next = recordsize_tail; + newrec->size = buf.len; + recordsize_tail = newrec; + + compress( &buf ); + + opdb_rec = new_Record (0, 0, ct++, buf.len, (const ubyte *)buf.data); + + if (opdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create record\n"); + } + + if (pdb_AppendRecord(opdb, opdb_rec)) { + fatal(MYNAME ": libpdb couldn't append record\n"); + } + +} + +static void create_bookmark( char *bmtext ) { + struct bookmark *newmark = (struct bookmark *) xcalloc( 1, sizeof(struct bookmark)); + newmark->next = bookmark_tail; + newmark->offset = offset; + newmark->text = bmtext; + bookmark_tail = newmark; +} + +static void docprintf( int maxlen, char *format, ... ) { + + char *txt = NULL; + char *txt2 = NULL; + va_list list; + int newlen; + int partlen; + + txt = (char *) xmalloc( maxlen ); + + va_start( list, format ); + newlen = vsprintf( txt, format, list ); + + txt2 = txt; + offset += newlen; + while (txt2 && *txt2 ) { + /* append to buffer what we can */ + partlen = BUFFER_SIZE-1-buf.len; + if ( buf.len + newlen + 1 > BUFFER_SIZE ) + { + strncpy( buf.data+buf.len, txt2, partlen ); + buf.data[BUFFER_SIZE-1] = '\0'; + txt2 += partlen; + newlen -= partlen; + buf.len = BUFFER_SIZE-1; + commit_buffer(); + NEW_BUFFER( &buf ); + } + else { + strcpy( buf.data+buf.len, txt2 ); + buf.len += newlen; + txt2 = NULL; + } + } + + xfree( txt ); +} + +static void docfinish() { + commit_buffer(); + write_header(); + write_bookmarks(); +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "wb", MYNAME); + out_fname = fname; + + mkshort_handle = mkshort_new_handle(); + mkshort_bookmark_handle = mkshort_new_handle(); + ct = 1; + offset = 1; + recordsize_tail = NULL; + bookmark_tail = NULL; + NEW_BUFFER( &buf ); +} + +static void +wr_deinit(void) +{ + fclose(file_out); + mkshort_del_handle(mkshort_handle); + mkshort_del_handle(mkshort_bookmark_handle); + + if ( dbname ) { + xfree(dbname); + dbname = NULL; + } +} + +static void +palmdoc_disp(const waypoint *wpt) +{ + int latint, lonint; + char tbuf[1024]; + time_t tm = wpt->creation_time; + long utmz; + double utme, utmn; + char utmzc; + + char bookmarktext[17]; + + if ( bmid ) { + sprintf( bookmarktext, "%6s:%9s", + wpt->shortname?wpt->shortname:"", + mkshort(mkshort_bookmark_handle, wpt->description)); + } + else { + sprintf( bookmarktext, "%16s", + mkshort(mkshort_bookmark_handle, wpt->description)); + } + + create_bookmark(xstrdup(bookmarktext)); + + lonint = abs(wpt->longitude); + latint = abs(wpt->latitude); + + GPS_Math_WGS84_To_UTM_EN(wpt->latitude, wpt->longitude, + &utme, &utmn, &utmz, &utmzc); + + if (tm == 0) + tm = time(NULL); + strftime(tbuf, sizeof(tbuf), "%d-%b-%Y", localtime(&tm)); + + docprintf(300, "%-16s %c%d %06.3f %c%d %06.3f (%ld%c %6.0f %7.0f)", + (global_opts.synthesize_shortnames) ? mkshort(mkshort_handle, wpt->description) : wpt->shortname, + wpt->latitude < 0 ? 'S' : 'N', abs(latint), 60.0 * (fabs(wpt->latitude) - latint), + wpt->longitude < 0 ? 'W' : 'E', abs(lonint), 60.0 * (fabs(wpt->longitude) - lonint), + utmz, utmzc, utme, utmn); + if (wpt->altitude != unknown_alt) + docprintf (100, " alt: %1.1f", wpt->altitude); + docprintf (10, "\n"); + if (strcmp(wpt->description, wpt->shortname)) { + docprintf(10+strlen(wpt->description), "%s\n", wpt->description); + } + if (wpt->gc_data.terr) { + if (wpt->gc_data.desc_short.utfstring) { + char *stripped_html = strip_html(&wpt->gc_data.desc_short); + docprintf (10+strlen(stripped_html), "\n%s\n", stripped_html); + xfree(stripped_html); + } + if (wpt->gc_data.desc_long.utfstring) { + char *stripped_html = strip_html(&wpt->gc_data.desc_long); + docprintf (10+strlen(stripped_html), "\n%s\n", stripped_html); + xfree(stripped_html); + } + if (wpt->gc_data.hint) { + char *hint = NULL; + if ( encrypt ) + hint = rot13( wpt->gc_data.hint ); + else + hint = xstrdup( wpt->gc_data.hint ); + docprintf (10+strlen(hint), "\nHint: %s\n", hint); + xfree( hint ); + } + } + else if (wpt->notes && (!wpt->description || strcmp(wpt->notes,wpt->description))) { + docprintf (10+strlen(wpt->notes), "%s\n", wpt->notes); + } + + if ( includelogs && wpt->gpx_extras ) { + xml_tag *root = wpt->gpx_extras; + xml_tag *curlog = NULL; + xml_tag *logpart = NULL; + curlog = xml_findfirst( root, "groundspeak:log" ); + while ( curlog ) { + time_t logtime = 0; + struct tm *logtm = NULL; + docprintf( 10, "\n" ); + + logpart = xml_findfirst( curlog, "groundspeak:type" ); + if ( logpart ) { + docprintf( 10+strlen(logpart->cdata), "%s by ", logpart->cdata ); + } + + logpart = xml_findfirst( curlog, "groundspeak:finder" ); + if ( logpart ) { + docprintf( 10+strlen(logpart->cdata), "%s on ", logpart->cdata ); + } + + logpart = xml_findfirst( curlog, "groundspeak:date" ); + if ( logpart ) { + logtime = xml_parse_time( logpart->cdata ); + logtm = localtime( &logtime ); + if ( logtm ) { + docprintf( 15, + "%2.2d/%2.2d/%4.4d\n", + logtm->tm_mon+1, + logtm->tm_mday, + logtm->tm_year+1900 + ); + } + } + + logpart = xml_findfirst( curlog, "groundspeak:log_wpt" ); + if ( logpart ) { + char *coordstr = NULL; + float lat = 0; + int latdeg = 0; + float lon = 0; + int londeg = 0; + coordstr = xml_attribute( logpart, "lat" ); + if ( coordstr ) { + lat = atof( coordstr ); + } + coordstr = xml_attribute( logpart, "lon" ); + if ( coordstr ) { + lon = atof( coordstr ); + } + latdeg = abs(lat); + londeg = abs(lon); + + docprintf( 30, + "%c %d\xb0 %.3f' %c %d\xb0 %.3f'\n", + + lat < 0 ? 'S' : 'N', latdeg, 60.0 * (fabs(lat) - latdeg), + lon < 0 ? 'W' : 'E', londeg, 60.0 * (fabs(lon) - londeg) + ); + } + + logpart = xml_findfirst( curlog, "groundspeak:text" ); + if ( logpart ) { + char *encstr = NULL; + char *s = NULL; + int encoded = 0; + encstr = xml_attribute( logpart, "encoded" ); + encoded = (encstr[0] != 'F'); + + if ( encrypt && encoded ) { + s = rot13( logpart->cdata ); + } + else { + s = xstrdup( logpart->cdata ); + } + + docprintf( 5+strlen(s), "%s", s ); + xfree( s ); + } + + docprintf( 10, "\n" ); + curlog = xml_findnext( root, curlog, "groundspeak:log" ); + } + } + if (! suppresssep) + docprintf(50, "---------------------------\n"); + else + docprintf(10, "\n"); + + +} + +static void +data_write(void) +{ + + if (NULL == (opdb = new_pdb())) { + fatal (MYNAME ": new_pdb failed\n"); + } + + if ( dbname ) { + strncpy( opdb->name, dbname, PDB_DBNAMELEN ); + } + else { + strncpy(opdb->name, out_fname, PDB_DBNAMELEN); + } + opdb->name[PDB_DBNAMELEN-1] = 0; + opdb->attributes = PDB_ATTR_BACKUP; + opdb->ctime = opdb->mtime = current_time() + 2082844800U; + opdb->type = DOC_TYPE; + opdb->creator = DOC_CREATOR; + opdb->version = 1; + + if (! suppresssep) + docprintf(50, "---------------------------\n"); + setshort_length(mkshort_handle, 20 ); + setshort_length(mkshort_bookmark_handle, 16-(bmid?7:0)); + setshort_whitespace_ok( mkshort_bookmark_handle, 0 ); + waypt_disp_all(palmdoc_disp); + + docfinish(); + pdb_Write(opdb, fileno(file_out)); +} + + +ff_vecs_t palmdoc_vecs = { + ff_type_file, + NULL, + wr_init, + NULL, + wr_deinit, + NULL, + data_write, + NULL, + palmdoc_args +}; + + diff --git a/pcx.c b/pcx.c new file mode 100644 index 000000000..4b4997b6d --- /dev/null +++ b/pcx.c @@ -0,0 +1,277 @@ +/* + Access to Garmin PCX5 files. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA +*/ + + +#include "defs.h" +#include "garmin_tables.h" +#include + +static FILE *file_in; +static FILE *file_out; +static void *mkshort_handle; +static char *deficon = NULL; + +#define MYNAME "PCX" + +static +arglist_t pcx_args[] = { + {"deficon", &deficon, "Default icon name", "Waypoint", + ARGTYPE_STRING }, + {0, 0, 0, 0, 0} +}; + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "r", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "w", MYNAME); + mkshort_handle = mkshort_new_handle(); +} + +static void +wr_deinit(void) +{ + fclose(file_out); + mkshort_del_handle(mkshort_handle); +} + +static void +data_read(void) +{ + char name[7], desc[40]; + double lat,lon; + char latdir, londir; + long alt; + int symnum; + char date[10]; + char time[9]; + char month[4]; + waypoint *wpt_tmp; + char ibuf[122]; + struct tm tm; + route_head *track_head = NULL; + int n; + char lathemi, lonhemi; + + + for(;fgets(ibuf, sizeof(ibuf), file_in);) { + switch (ibuf[0]) { + case 'W': + sscanf(ibuf, "W %6c %c%lf %c%lf %s %s %ld", + name, &latdir, &lat, &londir, &lon, + date, time, &alt); + sscanf(&ibuf[60], "%40c", + desc); + sscanf(&ibuf[116], "%d", + &symnum); + desc[sizeof(desc)-1] = '\0'; + name[sizeof(name)-1] = '\0'; + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + wpt_tmp->altitude = alt; + wpt_tmp->shortname = xstrdup(name); + wpt_tmp->description = xstrdup(desc); + wpt_tmp->icon_descr = mps_find_desc_from_icon_number(symnum, PCX); + + if (latdir == 'S') lat = -lat; + if (londir == 'W') lon = -lon; + wpt_tmp->longitude = ddmm2degrees(lon); + wpt_tmp->latitude = ddmm2degrees(lat); + waypt_add(wpt_tmp); + break; + case 'H': + /* Garmap2 has headers + "H(2 spaces)LATITUDE(some spaces)LONGTITUDE(etc... followed by);track + everything else is + H(2 chars)TN(tracknane\0) + */ + if (ibuf[3] == 'L' && ibuf[4] == 'A') { + track_head = route_head_alloc(); + track_head->rte_name = strdup("track"); + track_add_head(track_head); + } else if (ibuf[3] == 'T' && ibuf[4] == 'N') { + track_head = route_head_alloc(); + track_head->rte_name = strdup(&ibuf[6]); + track_add_head(track_head); + } + break; + case 'T': + n = sscanf(ibuf, "T %lf %lf %s %s %ld", + &lat, &lon, date, time, &alt); + + if (n == 0) { + /* Attempt alternate PCX format used by + * www.radroutenplaner.nrw.de */ + n = sscanf(ibuf, "T %c%lf %c%lf %s %s %ld", + &lathemi, &lat, &lonhemi, &lon, date, + time, &alt); + if (lathemi == 'S') lat = -lat; + if (lonhemi == 'W') lon = -lon; + } else if (n == 0) { + fatal(MYNAME ":Unrecognized track line '%s'", + ibuf); + } + + memset(&tm, 0, sizeof(tm)); + tm.tm_hour = atoi(time); + tm.tm_min = atoi(time+3); + tm.tm_sec = atoi(time+6); + tm.tm_mday = atoi(date); + strncpy(month, date+3, 3); + month[3] = 0; + tm.tm_mon = month_lookup(month); + tm.tm_year = atoi(date + 7) + 100; + wpt_tmp = waypt_new(); + wpt_tmp->creation_time = mktime(&tm) + get_tz_offset(); + wpt_tmp->latitude = lat; + wpt_tmp->longitude = lon; + wpt_tmp->altitude = alt; + /* Did we get a track point before a track header? */ + if (track_head == NULL) { + track_head = route_head_alloc(); + track_head->rte_name = strdup("Default"); + track_add_head(track_head); + } + route_add_wpt(track_head, wpt_tmp); + default: + ; + } + } +} + +static void +gpsutil_disp(const waypoint *wpt) +{ + double lon,lat; + int icon_token = 0; + char tbuf[1024]; + char *tp = tbuf; + time_t tm = wpt->creation_time; + + lon = degrees2ddmm(wpt->longitude); + lat = degrees2ddmm(wpt->latitude); + + if (tm == 0) + tm = current_time(); + strftime(tbuf, sizeof(tbuf), "%d-%b-%y %I:%M:%S", localtime(&tm)); + while (*tp) { + *tp = toupper(*tp); + tp++; + } + + icon_token = mps_find_icon_number_from_desc(wpt->icon_descr, PCX); + if (get_cache_icon(wpt)) { + icon_token = mps_find_icon_number_from_desc(get_cache_icon(wpt), PCX); + } + + + fprintf(file_out, "W %-6.6s %c%08.5f %c%011.5f %s %5d %-40.40s %5e %d\n", + global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, wpt->description) : + wpt->shortname, + lat < 0.0 ? 'S' : 'N', + fabs(lat), + lon < 0.0 ? 'W' : 'E', + fabs(lon), + tbuf, + -9999, + wpt->description, + 0.0, + icon_token); +} + +static void +pcx_track_hdr(const route_head *trk) +{ + fprintf(file_out, "\n\nH TN %s\n", trk->rte_name); + fprintf(file_out, "H LATITUDE LONGITUDE DATE TIME ALT\n"); + +} + +void +pcx_track_disp(const waypoint *wpt) +{ + double lon,lat; + char tbuf[100]; + struct tm *tm; + char *tp; + + lon = degrees2ddmm(wpt->longitude); + lat = degrees2ddmm(wpt->latitude); + + tm = localtime(&wpt->creation_time); + + strftime(tbuf, sizeof(tbuf), "%d-%b-%y %T", tm); + for (tp = tbuf; *tp; tp++) { + *tp = toupper(*tp); + } + fprintf(file_out, "T %c%08.5f %c%011.5f %s %.f\n", + lat < 0.0 ? 'S' : 'N', + fabs(lat), + lon < 0.0 ? 'W' : 'E', + fabs(lon), + tbuf, wpt->altitude); +} + + +static void +data_write(void) +{ +fprintf(file_out, +"H SOFTWARE NAME & VERSION\n" +"I PCX5 2.09\n" +"\n" +"H R DATUM IDX DA DF DX DY DZ\n" +"M G WGS 84 121 +0.000000e+00 +0.000000e+00 +0.000000e+00 +0.000000e+00 +0.000000e+00\n" +"\n" +"H COORDINATE SYSTEM\n" +"U LAT LON DM\n" +"\n" +"H IDNT LATITUDE LONGITUDE DATE TIME ALT DESCRIPTION PROXIMITY SYMBOL ;waypts\n"); + setshort_length(mkshort_handle, 6); + waypt_disp_all(gpsutil_disp); + + if (global_opts.objective == trkdata) { + track_disp_all(pcx_track_hdr, NULL, pcx_track_disp); + } +} + + +ff_vecs_t pcx_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL, + pcx_args +}; diff --git a/polygon.c b/polygon.c new file mode 100644 index 000000000..174eec4c6 --- /dev/null +++ b/polygon.c @@ -0,0 +1,298 @@ +/* + Inside/Outside polygon filter + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include "defs.h" + +#define MYNAME "Polygon filter" + +extern queue waypt_head; + +static char *polyfileopt = NULL; +static char *exclopt = NULL; + +#define OUTSIDE 0 +#define INSIDE 1 +#define LIMBO 2 +#define LIMBO_UP 4 +#define LIMBO_BEGIN 8 +#define BEGIN_UP 16 +#define BEGIN_HOR 32 +#define UP 64 + +typedef struct { + unsigned short state; + unsigned short override; +} extra_data; + +static +arglist_t polygon_args[] = { + {"file", &polyfileopt, "File containing vertices of polygon", + NULL, ARGTYPE_FILE | ARGTYPE_REQUIRED }, + {"exclude", &exclopt, "Exclude points inside the polygon", + NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + +static void polytest ( double lat1, double lon1, + double lat2, double lon2, + double lat3, double lon3, + unsigned short *state, int first, int last ) { + + if ( lat1 == lat3 ) { + if ( lat2 < lat3 ) { + /* going down */ + if (*state & LIMBO) { + if ( *state & LIMBO_UP ) { + *state = *state ^ INSIDE; + } + *state = *state & ~LIMBO &~LIMBO_UP; + } + else if (*state & LIMBO_BEGIN) { + if ( *state & BEGIN_HOR ) { + *state = *state & ~BEGIN_HOR; + } + else if ( last ) { + if ( *state & BEGIN_UP ) { + *state = *state ^ INSIDE; + } + *state = *state & ~LIMBO_BEGIN & ~BEGIN_UP; + } + } + else if ( first && (lon1 > lon3)) { + *state |= LIMBO_BEGIN; + } + } + else if ( lat2 == lat3 ) { + if ( first & (lon1 > lon3 || lon2 > lon3)) { + *state |= LIMBO_BEGIN | BEGIN_HOR; + } + else if (last && (*state & LIMBO_BEGIN) && (*state & LIMBO)) { + if ( (!!(*state & LIMBO_UP)) != (!!(*state & BEGIN_UP))) { + *state = *state ^ INSIDE; + } + *state = *state & ~LIMBO & ~LIMBO_UP & + ~LIMBO_BEGIN & ~BEGIN_UP; + } + else if ( *state & LIMBO ) { + /* do nothing */ + } + else { + if ( lon1 <= lon3 && lon2 > lon3 ) { + if ( *state & UP ) { + *state = *state | LIMBO_UP & ~UP; + } + *state = *state | LIMBO; + } + } + } + else { + /* going up */ + if (*state & LIMBO) { + if ( !(*state & LIMBO_UP) ) { + *state = *state ^ INSIDE; + } + *state = *state & ~LIMBO & ~LIMBO_UP; + } + else if (*state & LIMBO_BEGIN) { + if ( *state & BEGIN_HOR ) { + *state = *state & ~BEGIN_HOR | BEGIN_UP; + } + else if ( last ) { + if ( !(*state & BEGIN_UP) ) { + *state = *state ^ INSIDE; + } + *state = *state & ~LIMBO_BEGIN & ~BEGIN_UP; + } + } + else if ( first && (lon1 > lon3)) { + *state |= LIMBO_BEGIN | BEGIN_UP; + } + } + *state = *state & ~UP; + } + else if ( lat2 == lat3 ) { + if ( lat1 < lat3 ) { + if ( last ) { + if ( *state & BEGIN_UP ) { + *state = *state ^ INSIDE; + } + *state = *state & ~LIMBO_BEGIN & ~BEGIN_UP; + } + else if ( lon2 > lon3 ) { + *state |= LIMBO; + } + } + /* no case for lat1==lat3; that's above */ + else { + if ( last ) { + if ( !(*state & BEGIN_UP) ) { + *state = *state ^ INSIDE; + } + *state = *state & ~LIMBO_BEGIN & ~BEGIN_UP; + } + else if ( lon2 > lon3 ) { + *state |= LIMBO | LIMBO_UP; + } + else { + *state |= UP; + } + } + } + else { + if ( (lat1 > lat3 && lat2 < lat3) || + (lat1 < lat3 && lat2 > lat3)) { + /* we only care if the lines might intersect */ + if ( lon1 > lon3 && lon2 > lon3 ) { + *state = *state ^ INSIDE; + } + else if (!(lon1 <= lon3 && lon2 <= lon3)) { + /* we're inside the bbox of a diagonal line. math time. */ + double loni = lon1+(lon2-lon1)/(lat2-lat1)*(lat3-lat1); + if ( loni > lon3 ) { + *state = *state ^ INSIDE; + } + } + } + } + +} + +#define BADVAL 999999 + +void +polygon_process(void) +{ + queue * elem, * tmp; + waypoint * waypointp; + extra_data *ed; + double lat1, lon1, lat2, lon2; + double olat, olon; + int fileline = 0; + int first = 1; + int last = 0; + + FILE *polyfile = xfopen( polyfileopt, "r", MYNAME ); + + olat = olon = lat1 = lon1 = lat2 = lon2 = BADVAL; + while ( !feof(polyfile)) { + char line[200]; + char *pound = NULL; + int argsfound = 0; + + fgets( line, sizeof(line), polyfile ); + + fileline++; + + pound = strchr( line, '#' ); + if ( pound ) *pound = '\0'; + + lat2 = lon2 = BADVAL; + argsfound = sscanf( line, "%lf %lf", &lat2, &lon2 ); + + if ( argsfound != 2 && strspn(line, " \t\n") < strlen(line)) { + warning(MYNAME + ": Warning: Polygon file contains unusable vertex on line %d.\n", + fileline ); + } + else if ( lat1 != BADVAL && lon1 != BADVAL && + lat2 != BADVAL && lon2 != BADVAL ) { + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + + waypointp = (waypoint *)elem; + if ( waypointp->extra_data ) { + ed = (extra_data *) waypointp->extra_data; + } + else { + ed = (extra_data *) xcalloc(1, sizeof(*ed)); + ed->state = OUTSIDE; + ed->override = 0; + waypointp->extra_data = (extra_data *) ed; + } + if ( lat2 == waypointp->latitude && + lon2 == waypointp->longitude ) { + ed->override = 1; + } + if ( olat != BADVAL && olon != BADVAL && + olat == lat2 && olon == lon2 ) { + last = 1; + } + polytest( lat1, lon1, lat2, lon2, + waypointp->latitude, + waypointp->longitude, + &ed->state, first, last ); + first = 0; + last = 0; + } + } + if ( olat != BADVAL && olon != BADVAL && + olat == lat2 && olon == lon2 ) { + olat = BADVAL; + olon = BADVAL; + lat1 = BADVAL; + lon1 = BADVAL; + first = 1; + } + else if ( lat1 == BADVAL || lon1 == BADVAL ) { + olat = lat2; + olon = lon2; + lat1 = lat2; + lon1 = lon2; + } + else { + lat1 = lat2; + lon1 = lon2; + } + } + + fclose(polyfile); + + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + waypoint *wp = (waypoint *) elem; + ed = (extra_data *) wp->extra_data; + wp->extra_data = NULL; + if ( ed ) { + if ( ed->override ) ed->state = INSIDE; + if (((ed->state & INSIDE) == OUTSIDE ) == (exclopt == NULL)) { + waypt_del(wp); + waypt_free(wp); + } + xfree( ed ); + } + } +} + +void +polygon_init(const char *args) { + /* do nothing */ +} + +void +polygon_deinit(void) { + /* do nothing */ +} + +filter_vecs_t polygon_vecs = { + polygon_init, + polygon_process, + polygon_deinit, + NULL, + polygon_args +}; diff --git a/position.c b/position.c new file mode 100644 index 000000000..9105dfff0 --- /dev/null +++ b/position.c @@ -0,0 +1,372 @@ +/* + Distance Between Points Filter(s) + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include "defs.h" +#include "grtcirc.h" + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +extern queue waypt_head; +static route_head *cur_rte = NULL; + +static double pos_dist; +static char *distopt = NULL; +static char *purge_duplicates = NULL; +static char *latopt = NULL; +static char *lonopt = NULL; +static char *exclopt = NULL; +static char *nosort = NULL; + +waypoint * home_pos; + +typedef struct { + double distance; +} extra_data; + +static +arglist_t position_args[] = { + {"distance", &distopt, "Maximum positional distance", + NULL, ARGTYPE_FLOAT | ARGTYPE_REQUIRED }, + {"all", &purge_duplicates, + "Suppress all points close to other points", + NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + +static +arglist_t radius_args[] = { + {"lat", &latopt, "Latitude for center point (D.DDDDD)", + NULL, ARGTYPE_FLOAT | ARGTYPE_REQUIRED }, + {"lon", &lonopt, "Longitude for center point (D.DDDDD)", + NULL, ARGTYPE_FLOAT | ARGTYPE_REQUIRED }, + {"distance", &distopt, "Maximum distance from center", + NULL, ARGTYPE_FLOAT | ARGTYPE_REQUIRED }, + {"exclude", &exclopt, "Exclude points close to center", + NULL, ARGTYPE_BOOL }, + {"nosort", &nosort, "Inhibit sort by distance to center.", + NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + +static double +gc_distance(double lat1, double lon1, double lat2, double lon2) +{ + return gcdist( + (lat1 * M_PI) / 180.0, + (lon1 * M_PI) / 180.0, + (lat2 * M_PI) / 180.0, + (lon2 * M_PI) / 180.0 + ); +} + +static int +position_comp(const void * a, const void * b) +{ + const waypoint *x1 = *(waypoint **)a; + const waypoint *x2 = *(waypoint **)b; + double latdiff, londiff, max; + + /* + * this compare makes the assumption that things will fall into + * order by declaring their biggest single axial difference. + * It is much less math than distance and bearing from some random + * point. + */ + + londiff = (x1->longitude - + x2->longitude) * 1000000.0; + latdiff = (x1->latitude - + x2->latitude) * 1000000.0; + + max = fabs(londiff) >= fabs(latdiff) ? floor(londiff) : floor(latdiff); + + if (max < 0) + return (-1); + else if (max > 0) + return (1); + + return(0); +} + +static int +dist_comp(const void * a, const void * b) +{ + const waypoint *x1 = *(waypoint **)a; + const waypoint *x2 = *(waypoint **)b; + extra_data *x1e = (extra_data *) x1->extra_data; + extra_data *x2e = (extra_data *) x2->extra_data; + + if (x1e->distance > x2e->distance) + return 1; + if (x1e->distance < x2e->distance) + return -1; + return 0; + +} + +/* tear through a waypoint queue, processing points by distance */ +static void +position_runqueue(queue *q, int nelems, int qtype) +{ + queue * elem, * tmp; + waypoint ** comp; + double dist; + int i, j; + int del = 0; + + comp = (waypoint **) xcalloc(nelems, sizeof(*comp)); + + i = 0; + + QUEUE_FOR_EACH(q, elem, tmp) { + comp[i] = (waypoint *)elem; + i++; + } + + if (qtype == wptdata) + qsort(comp, nelems, sizeof(waypoint *), position_comp); + + for (i = 1, j = 0 ; i < nelems ; i++) { + dist = gc_distance(comp[j]->latitude, + comp[j]->longitude, + comp[i]->latitude, + comp[i]->longitude); + + /* convert radians to integer feet */ + dist = (int)(5280*tomiles(dist)); + + if (dist <= pos_dist) { + switch (qtype) { + case wptdata: + waypt_del(comp[i]); + waypt_free(comp[i]); + del = !!purge_duplicates; + break; + case trkdata: + case rtedata: + route_del_wpt(cur_rte, comp[i]); + del = !!purge_duplicates; + break; + default: + break; + } + } + else if (del ) { + switch (qtype) { + case wptdata: + waypt_del(comp[i]); + waypt_free(comp[i]); + del = 0; + break; + case trkdata: + case rtedata: + route_del_wpt(cur_rte, comp[i]); + del = 0; + break; + default: + break; + } + } else { + j = i; /* advance last use point */ + } + } + if ( del ) { + switch (qtype) { + case wptdata: + waypt_del(comp[nelems-1]); + waypt_free(comp[nelems-1]); + break; + case trkdata: + case rtedata: + route_del_wpt(cur_rte, comp[i]); + break; + default: + break; + } + } + + if (comp) + xfree(comp); +} + +static void +position_process_route(const route_head * rh) { + int i = rh->rte_waypt_ct; + + if (i) { + cur_rte = (route_head *)rh; + position_runqueue((queue *)&rh->waypoint_list, i, rtedata); + cur_rte = NULL; + } + +} + +static void +position_noop(){ +} + +void position_process() +{ + int i = waypt_count(); + + if (i) + position_runqueue(&waypt_head, i, wptdata); + + route_disp_all(position_process_route, position_noop, position_noop); + track_disp_all(position_process_route, position_noop, position_noop); +} + +void +position_init(const char *args) { + char *fm; + + pos_dist = 0; + + if (distopt) { + pos_dist = strtod(distopt, &fm); + + if ((*fm == 'm') || (*fm == 'M')) { + /* distance is meters */ + pos_dist *= 3.2802; + } + } +} + +void +position_deinit(void) { +} + +void +radius_process(void) +{ + queue * elem, * tmp; + waypoint * waypointp; + double dist; + waypoint ** comp; + int i, wc; + queue temp_head; + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + extra_data *ed; + + waypointp = (waypoint *)elem; + dist = gc_distance(waypointp->latitude, + waypointp->longitude, + home_pos->latitude, + home_pos->longitude); + + /* convert radians to float point statute miles */ + dist = tomiles(dist); + + if ((dist >= pos_dist) == (exclopt == NULL)) { + waypt_del(waypointp); + waypt_free(waypointp); + continue; + } + + ed = (extra_data *) xcalloc(1, sizeof(*ed)); + ed->distance = dist; + waypointp->extra_data = ed; + } + + wc = waypt_count(); + QUEUE_INIT(&temp_head); + + comp = (waypoint **) xcalloc(wc, sizeof(*comp)); + + i = 0; + + /* + * Create an array of remaining waypoints, popping them off the + * master queue as we go. This gives us something reasonable + * for qsort. + */ + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + waypoint *wp = (waypoint *) elem; + comp[i] = wp; + waypt_del(wp); + i++; + } + + if (!nosort) { + qsort(comp, wc, sizeof(waypoint *), dist_comp); + } + + /* + * The comp array is now sorted by distance. As we run through it, + * we push them back onto the master wp list, letting us pass them + * on through in the modified order. + */ + for (i = 0; i < wc; i++) { + waypoint * wp = comp[i]; + waypt_add(wp); + xfree(wp->extra_data); + } + + xfree(comp); +} + +void +radius_init(const char *args) { + char *fm; + + pos_dist = 0; + + if (distopt) { + pos_dist = strtod(distopt, &fm); + + if ((*fm == 'k') || (*fm == 'K')) { + /* distance is kilometers, convert to feet */ + pos_dist *= .6214; + } + } + + home_pos = (waypoint *) xcalloc(sizeof(*home_pos), 1); + + if (latopt) + home_pos->latitude = atof(latopt); + if (lonopt) + home_pos->longitude = atof(lonopt); +} + +void +radius_deinit(void) { + if (home_pos) + xfree(home_pos); +} + +filter_vecs_t position_vecs = { + position_init, + position_process, + position_deinit, + NULL, + position_args +}; + +filter_vecs_t radius_vecs = { + radius_init, + radius_process, + radius_deinit, + NULL, + radius_args +}; diff --git a/psitrex.c b/psitrex.c new file mode 100644 index 000000000..9166f830f --- /dev/null +++ b/psitrex.c @@ -0,0 +1,810 @@ +/* + Access to PsiTrex text files. + Based on information provided by Ian Cowley. + + Copyright (C) 2003 Mark Bradley, mrcb.gpsb@osps.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + */ + +#include +#include + +#include "defs.h" +#include "garmin_tables.h" +#include + +#define MYNAME "PSITREX" + +typedef enum { + ltrimEOL = 1 , /* skip spaces & tabs to start; ends on EOL */ + EOL, /* don't skip spaces and tabs to start; end on EOL */ + comma, /* skip spaces & tabs to start; ends on comma or EOL */ + whitespace, /* skip spaces & tabs to start; ends on white space or EOL */ + wscomma /* skip spaces & tabs to start; ends on white space, comma or EOL */ +} psit_tokenSep_type; + +typedef struct psit_icon_mapping { + const int value; + const char *icon; +} psit_icon_mapping_t; + +static FILE *psit_file_in; +static FILE *psit_file_out; +static void *mkshort_handle; + +/* 2 = not written any tracks out + 1 = change of track to write out track header + 0 = in the middle of writing out track datapoints, so don't write a header */ +static int psit_track_state = 2; + +static char psit_current_token[256]; + +char *snlen; + +static +arglist_t psit_args[] = { +/* {"snlen", &snlen, "Length of generated shortnames", + NULL, ARGTYPE_INT }, */ + {0, 0, 0, 0, 0} +}; + +/* Taken from PsiTrex 1.13 */ +const psit_icon_mapping_t psit_icon_value_table[] = { + { 0x00, "anchor" }, + { 0x06, "dollar" }, + { 0x07, "fish" }, + { 0x08, "fuel" }, + { 0x0a, "house" }, + { 0x0b, "knife" }, + { 0x0d, "mug" }, + { 0x0e, "skull" }, + { 0x12, "wpt_dot" }, + { 0x13, "wreck" }, + { 0x15, "mob" }, + { 0x0096, "boat_ramp" }, + { 0x0097, "camp" }, + { 0x0098, "restrooms" }, + { 0x0099, "showers" }, + { 0x009a, "drinking_wtr" }, + { 0x009b, "phone" }, + { 0x009c, "1st_aid" }, + { 0x009d, "info" }, + { 0x009e, "parking" }, + { 0x009f, "park" }, + { 0x00a0, "picnic" }, + { 0x00a1, "scenic" }, + { 0x00a2, "skiing" }, + { 0x00a3, "swimming" }, + { 0x00a4, "dam" }, + { 0x00a6, "danger" }, + { 0x00a9, "ball" }, + { 0x00aa, "car" }, + { 0x00ab, "deer" }, + { 0x00ac, "shpng_cart" }, + { 0x00ad, "lodging" }, + { 0x00ae, "mine" }, + { 0x00af, "trail_head" }, + { 0x00b0, "truck_stop" }, + { 0x00b2, "flag" }, + { 0x2005, "golf" }, + { 0x2006, "sml_cty" }, + { 0x2007, "med_cty" }, + { 0x2008, "lrg_cty" }, + { 0x200c, "amuse_pk" }, + { 0x200d, "bowling" }, + { 0x200e, "car_rental" }, + { 0x200f, "car_repair" }, + { 0x2010, "fastfood" }, + { 0x2011, "fitness" }, + { 0x2012, "movie" }, + { 0x2013, "museum" }, + { 0x2014, "pharmacy" }, + { 0x2015, "pizza" }, /* how specific does this really need to be? C'mon! */ + { 0x2016, "post_ofc" }, + { 0x2017, "rv_park" }, + { 0x2018, "school" }, + { 0x2019, "stadium" }, + { 0x201a, "store" }, + { 0x201b, "zoo" }, + { 0x201c, "gas_plus" }, + { 0x201d, "faces" }, + { 0x2022, "weigh_sttn" }, + { 0x2023, "toll_booth" }, + { 0x2029, "bridge" }, + { 0x202a, "building" }, + { 0x202b, "cemetery" }, + { 0x202c, "church" }, + { 0x202e, "crossing" }, + { 0x2032, "oil_field" }, + { 0x2033, "tunnel" }, + { 0x2035, "forest" }, + { 0x2036, "summit" }, + { 0x203f, "geocache" }, + { 0x2040, "geocache_fnd" }, + { 0x4000, "airport" }, + { 0x4007, "tall_tower" }, + { 0x4008, "short_tower" }, + { 0x4009, "glider" }, + { 0x400a, "ultralight" }, + { 0x400b, "parachute" }, + { 0x4012, "seaplane" }, + { -1, NULL } +}; + +const char * +psit_find_desc_from_icon_number(const int icon) +{ + const psit_icon_mapping_t *i; + + for (i = psit_icon_value_table; i->icon; i++) { + if (icon == i->value) { + return i->icon; + } + } + return ""; +} + +int +psit_find_icon_number_from_desc(const char *desc) +{ + const psit_icon_mapping_t *i; + int def_icon = 18; + + if (!desc) { + return def_icon; + } + + for (i = psit_icon_value_table; i->icon; i++) { + if (case_ignore_strcmp(desc,i->icon) == 0) { + return i->value; + } + } + if (atoi(desc) > 0) return atoi(desc); + return def_icon; +} + +static void +psit_rd_init(const char *fname) +{ + psit_file_in = xfopen(fname, "r", MYNAME); +} + +static void +psit_rd_deinit(void) +{ + fclose(psit_file_in); +} + +static void +psit_wr_init(const char *fname) +{ + psit_file_out = xfopen(fname, "w", MYNAME); +} + +static void +psit_wr_deinit(void) +{ + fclose(psit_file_out); +} + +/* + * get characters until and including terminating NULL from psit_file_in + * and write into buf. + */ +static void +psit_getToken(FILE *psit_file, char *buf, size_t sz, psit_tokenSep_type delimType) +{ + int c; +char *buf2 = buf; /* MRCB debug */ + + *buf = 0; + + if (delimType != EOL) { + while ((c = fgetc (psit_file)) != EOF) { + if (!isspace(c)) break; + } + } + + if (feof(psit_file)) return; + + if (delimType == EOL) { + c = fgetc (psit_file); + } + + if (c == '#') { + if (fgets(buf, sz, psit_file) == NULL) { + *buf = 0; + return; + } + /* use recursion to skip multiple comment lines or just to return the next token */ + psit_getToken(psit_file, buf, sz, delimType); + return; + } + + if ((delimType == EOL) || (delimType == ltrimEOL)) { + *buf = c; + buf++; + fgets(buf, sz-1, psit_file); + return; + } + + while (sz--) { + *buf++ = c; + if ((c = fgetc (psit_file)) == EOF) { + *buf = 0; + return; + } + if (((c == 0) || isspace(c)) && + ((delimType == whitespace) || (delimType == wscomma)) ) { + *buf = 0; + return; + } + if (((delimType == comma) || (delimType == wscomma)) && + (c == ',')) { + *buf = 0; + return; + } + } +} + + +/* + * test if a token is known + * + */ +static int +psit_isKnownToken(char *buf) +{ + if (strcmp(buf, "Track:") == 0) return 0; + if (strcmp(buf, "Route:") == 0) return 0; + if (strcmp(buf, "Waypoint:") == 0) return 0; + if (strcmp(buf, "Map:") == 0) return 0; + return 1; +} + +/* + * read in from file a waypoint record + * MRCB + */ +static void +psit_waypoint_r(FILE *psit_file, waypoint **wpt) +{ + int garmin_icon_num; + + waypoint *thisWaypoint; + double psit_altitude = unknown_alt; + double psit_depth = unknown_alt; + + if (strlen(psit_current_token) > 0) { + thisWaypoint = waypt_new(); + + thisWaypoint->latitude = atof(psit_current_token); + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma); + thisWaypoint->longitude = atof(psit_current_token); + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma); + if (psit_current_token[0] == '*') { + thisWaypoint->altitude = unknown_alt; + } + else { + thisWaypoint->altitude = atof(psit_current_token); + } + + /* the name */ + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma); + rtrim(psit_current_token); + thisWaypoint->shortname = xstrdup(psit_current_token); + thisWaypoint->description = xstrdup(""); + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), ltrimEOL); + rtrim(psit_current_token); + /* since PsiTrex only deals with Garmins, let's use the "proper" Garmin icon name */ + /* convert the PsiTrex name to the number, which is the PCX one; from there to Garmin desc */ + garmin_icon_num = psit_find_icon_number_from_desc(psit_current_token); + thisWaypoint->icon_descr = mps_find_desc_from_icon_number(garmin_icon_num, PCX); + + waypt_add(thisWaypoint); + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), wscomma); + } +} + +/* + * write out to file a waypoint record + * MRCB + */ +static void +psit_waypoint_w(FILE *psit_file, const waypoint *wpt) +{ + int icon; + char *src; + const char *ident; + int display = 1; + int colour = 0; /* (unknown colour) black is 1, white is 16 */ + + fprintf(psit_file, "%11.6f,%11.6f,", + wpt->latitude, + wpt->longitude); + + if (wpt->altitude == unknown_alt) + fprintf(psit_file, "********,"); + else + fprintf(psit_file, "%8.2f,", + wpt->altitude); + + ident = global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, src) : + wpt->shortname; + + fprintf(psit_file, " %-6s, ", ident); + icon = mps_find_icon_number_from_desc(wpt->icon_descr, PCX); + + if (get_cache_icon(wpt) && wpt->icon_descr && (strcmp(wpt->icon_descr, "Geocache Found") != 0)) { + icon = mps_find_icon_number_from_desc(get_cache_icon(wpt), PCX); + } + + ident = psit_find_desc_from_icon_number(icon); + if (strlen(ident) == 0) + fprintf(psit_file, "%1d\n", icon); + else + fprintf(psit_file, "%s\n", ident); + +} + +static void +psit_waypoint_w_wrapper(const waypoint *wpt) +{ + psit_waypoint_w(psit_file_out, wpt); +} + +/* + * read in from file a route record + * MRCB + */ +static void +psit_route_r(FILE *psit_file, route_head **rte) +{ + char rtename[256]; + unsigned int rte_num; + + int garmin_icon_num; + + time_t dateTime = 0; + route_head *rte_head; + unsigned int rte_count; + + waypoint *thisWaypoint; + double psit_altitude = unknown_alt; + double psit_depth = unknown_alt; + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), ltrimEOL); + + if (strlen(psit_current_token) == 0) { + strcpy(rtename, "ROUTE"); + } + else { + strcpy(rtename, psit_current_token); + } + + rtrim(rtename); + + rte_head = route_head_alloc(); + rte_head->rte_name = xstrdup(rtename); + route_add_head(rte_head); + *rte = rte_head; + + rte_num = 0; + + rte_count = 0; + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), wscomma); + + while (psit_isKnownToken(psit_current_token) != 0) { + if (strlen(psit_current_token) > 0) { + thisWaypoint = waypt_new(); + + thisWaypoint->latitude = atof(psit_current_token); + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma); + thisWaypoint->longitude = atof(psit_current_token); + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma); + if (psit_current_token[0] == '*') { + thisWaypoint->altitude = unknown_alt; + } + else { + thisWaypoint->altitude = atof(psit_current_token); + } + + /* the name */ + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma); + rtrim(psit_current_token); + thisWaypoint->shortname = xstrdup(psit_current_token); + thisWaypoint->description = xstrdup(""); + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), ltrimEOL); + rtrim(psit_current_token); + /* since PsiTrex only deals with Garmins, let's use the "proper" Garmin icon name */ + /* convert the PsiTrex name to the number, which is the PCX one; from there to Garmin desc */ + garmin_icon_num = psit_find_icon_number_from_desc(psit_current_token); + thisWaypoint->icon_descr = mps_find_desc_from_icon_number(garmin_icon_num, PCX); + + route_add_wpt(rte_head, thisWaypoint); + + if (feof(psit_file)) break; + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), wscomma); + } + else break; + } +} + +/* + * write out to file a route header + * MRCB + */ +static void +psit_routehdr_w(FILE *psit_file, const route_head *rte) +{ + char hdr[20]; + unsigned int rte_datapoints; + char *rname; + + waypoint *testwpt; + time_t uniqueValue; + int allWptNameLengths; + + queue *elem, *tmp; + + /* total nodes (waypoints) this route */ + rte_datapoints = 0; + allWptNameLengths = 0; + + if (rte->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid route - treat as a placeholder for now */ + QUEUE_FOR_EACH(&rte->waypoint_list, elem, tmp) { + testwpt = (waypoint *)elem; + if (rte_datapoints == 0) { + uniqueValue = testwpt->creation_time; + } + rte_datapoints++; + } + + if (uniqueValue == 0) { + uniqueValue = current_time(); + } + + /* route name */ + if (!rte->rte_name) { + sprintf(hdr, "Route%04x", uniqueValue); + rname = xstrdup(hdr); + } + else + rname = xstrdup(rte->rte_name); + + fprintf(psit_file, "Route: %s\n", + rname); + xfree(rname); + } +} + +static void +psit_routehdr_w_wrapper(const route_head *rte) +{ + psit_routehdr_w(psit_file_out, rte); +} + + +/* + * read in from file a track record + * MRCB + */ +static void +psit_track_r(FILE *psit_file, route_head **trk) +{ + char tbuf[100]; + char trkname[256]; + unsigned int trk_num; + + struct tm tmTime; + time_t dateTime = 0; + route_head *track_head; + unsigned int trk_count; + + waypoint *thisWaypoint; + double psit_altitude = unknown_alt; + double psit_depth = unknown_alt; + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), ltrimEOL); + if (strlen(psit_current_token) == 0) { + strcpy(trkname, "TRACK"); + } + else { + strcpy(trkname, psit_current_token); + } + + rtrim(trkname); + + trk_num = 0; + + trk_count = 0; + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), wscomma); + + while (psit_isKnownToken(psit_current_token) != 0) { + if (strlen(psit_current_token) > 0) { + thisWaypoint = waypt_new(); + + thisWaypoint->latitude = atof(psit_current_token); + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma); + thisWaypoint->longitude = atof(psit_current_token); + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), comma); + if (psit_current_token[0] == '*') { + thisWaypoint->altitude = unknown_alt; + } + else { + thisWaypoint->altitude = atof(psit_current_token); + } + + /* date portion of the date time DD/MM/YY */ + psit_getToken(psit_file, psit_current_token, + sizeof(psit_current_token), whitespace); + sscanf(psit_current_token, "%02d/%02d/%02d", + &(tmTime.tm_mday) , &(tmTime.tm_mon), + &(tmTime.tm_year)); + + /* years are less 1900 in the tm struct */ + tmTime.tm_year += (tmTime.tm_year > 50 ? 0 : 100); + /* months are 0 to 11 in the tm struct */ + tmTime.tm_mon--; + /* time portion of the date time hh:mm:ss */ + psit_getToken(psit_file,psit_current_token, + sizeof(psit_current_token), wscomma); + sscanf(psit_current_token, "%02d:%02d:%02d", + &(tmTime.tm_hour) , &(tmTime.tm_min), + &(tmTime.tm_sec)); + + tmTime.tm_isdst = 0; + dateTime = mktime(&tmTime) + get_tz_offset(); + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), whitespace); + + if (strcmp(psit_current_token, "1") == 0) { + track_head = route_head_alloc(); + /* Add a number to the track name. With Garmins, the "first" tracklog is usually ACTIVE LOG + the second is ACTIVE LOG001 and so on */ + if (trk_num > 0) { + sprintf(tbuf, "%s%03d", trkname, trk_num); + track_head->rte_name = xstrdup(tbuf); + } + else { + track_head->rte_name = xstrdup(trkname); + } + trk_num++; + track_add_head(track_head); + } + + thisWaypoint->creation_time = dateTime; + thisWaypoint->centiseconds = 0; + route_add_wpt(track_head, thisWaypoint); + + if (feof(psit_file)) break; + + psit_getToken(psit_file,psit_current_token,sizeof(psit_current_token), wscomma); + } + else break; + } +} + +/* + * write out to file a tracklog header + * MRCB + */ +static void +psit_trackhdr_w(FILE *psit_file, const route_head *trk) +{ + char hdr[30]; + unsigned int trk_datapoints; + char *tname; + waypoint *testwpt; + time_t uniqueValue; + + queue *elem, *tmp; + + if (psit_track_state == 2) { + /* total nodes (waypoints) this track */ + trk_datapoints = 0; + if (trk->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid track - treat as a placeholder for now */ + QUEUE_FOR_EACH(&trk->waypoint_list, elem, tmp) { + if (trk_datapoints == 0) { + testwpt = (waypoint *)elem; + uniqueValue = testwpt->creation_time; + } + trk_datapoints++; + } + + if (uniqueValue == 0) { + uniqueValue = current_time(); + } + + /* track name */ + if (!trk->rte_name) { + sprintf(hdr, "Track%04x", uniqueValue); + tname = xstrdup(hdr); + } + else + tname = xstrdup(trk->rte_name); + + fprintf (psit_file, "Track: %s\n", + tname); + + xfree(tname); + } + } + psit_track_state = 1; +} + +static void +psit_trackhdr_w_wrapper(const route_head *trk) +{ + psit_trackhdr_w(psit_file_out, trk); +} + + +/* + * write out to file a tracklog datapoint + * MRCB + */ +static void +psit_trackdatapoint_w(FILE *psit_file, const waypoint *wpt) +{ + time_t t = wpt->creation_time; + struct tm *tmTime = gmtime(&t); + + double psit_altitude = wpt->altitude; + double psit_proximity = unknown_alt; + double psit_depth = unknown_alt; + + fprintf(psit_file, "%11.6f,%11.6f,", + wpt->latitude, + wpt->longitude); + + if (wpt->altitude == unknown_alt) + fprintf(psit_file, "********, "); + else + fprintf(psit_file, "%8.2f, ", + wpt->altitude); + + /* Following date time format is fixed and reveals the origin of PsiTrex (i.e. the UK) */ + fprintf(psit_file, "%02d/%02d/%02d %02d:%02d:%02d,", + tmTime->tm_mday, + tmTime->tm_mon+1, + tmTime->tm_year % 100, + tmTime->tm_hour, + tmTime->tm_min, + tmTime->tm_sec); + + fprintf(psit_file," %d\n", psit_track_state); + psit_track_state = 0; +} + +static void +psit_trackdatapoint_w_wrapper(const waypoint *wpt) +{ + psit_trackdatapoint_w(psit_file_out, wpt); +} + + +static void +psit_read(void) +{ + waypoint *wpt; + route_head *rte; + route_head *trk; + +#ifdef DUMP_ICON_TABLE + printf("static icon_mapping_t icon_table[] = {\n"); +#endif + + psit_getToken(psit_file_in, psit_current_token, sizeof(psit_current_token), whitespace); + + do { + if (strlen(psit_current_token) == 0) break; + + if (strcmp(psit_current_token, "Track:") == 0) { + if (global_opts.objective == trkdata) { + psit_track_r(psit_file_in, &trk); + } + else break; /* psitrex files only have one format in; */ + /* if this is a track file and we don't want them, them bail out */ + } + else if (strcmp(psit_current_token, "Route:") == 0) { + if (global_opts.objective == rtedata) { + psit_route_r(psit_file_in, &rte); + } + else break; /* ditto, but for routes */ + } + else { + /* Must be waypoints in this file */ + if (global_opts.objective == wptdata) { + psit_waypoint_r(psit_file_in, &wpt); +#ifdef DUMP_ICON_TABLE + printf("\t{ %4u, \"%s\" },\n", icon, wpt->shortname); +#endif + + } + else break; + } + } while (!feof(psit_file_in)); + + return; + +#ifdef DUMP_ICON_TABLE + printf("\t{ -1, NULL },\n"); + printf("};\n"); +#endif +} + +static void +psit_noop(const route_head *wp) +{ + /* no-op */ +} + +void +psit_write(void) +{ + int short_length; + + if (snlen) + short_length = atoi(snlen); + else + short_length = 10; + + mkshort_handle = mkshort_new_handle(); + + setshort_length(mkshort_handle, short_length); + setshort_whitespace_ok(mkshort_handle, 0); + + psit_track_state = 2; + + if (global_opts.objective == wptdata) { + waypt_disp_all(psit_waypoint_w_wrapper); + } + if (global_opts.objective == rtedata) { + route_disp_all(psit_routehdr_w_wrapper, psit_noop, psit_waypoint_w_wrapper); + } + if (global_opts.objective == trkdata) { + track_disp_all(psit_trackhdr_w_wrapper, psit_noop, psit_trackdatapoint_w_wrapper); + } + + mkshort_del_handle(mkshort_handle); + +} + +ff_vecs_t psit_vecs = { + ff_type_file, + psit_rd_init, + psit_wr_init, + psit_rd_deinit, + psit_wr_deinit, + psit_read, + psit_write, + NULL, + psit_args +}; diff --git a/psp.c b/psp.c new file mode 100644 index 000000000..01fde6645 --- /dev/null +++ b/psp.c @@ -0,0 +1,469 @@ +/* + PocketStreets 2002 Pushpin Files + Contributed to gpsbabel by Alex Mottram (geo_alexm at cox-internet.com) + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include + +#define MYNAME "PSP" + +#define MAXPSPSTRINGSIZE 256 +#define MAXPSPOUTPUTPINS 8192 /* Any more points than this is ludicrous */ + +static FILE *psp_file_in; +static FILE *psp_file_out; +static FILE *mkshort_handle; + +static int +psp_fread(void *buff, size_t size, size_t members, FILE * fp) +{ + size_t br; + + br = fread(buff, size, members, fp); + + if (br != members) { + fatal(MYNAME ": requested to read %d bytes, read %d bytes.\n", members, br); + } + + return (br); +} + +static double +psp_fread_double(FILE *fp) +{ + unsigned char buf[8]; + unsigned char sbuf[8]; + + psp_fread(buf, 1, 8, fp); + le_read64(sbuf, buf); + return *(double *) sbuf; +} + +static void +psp_fwrite_double(double x, FILE *fp) +{ + unsigned char *cptr = (unsigned char *)&x; + unsigned char cbuf[8]; + + le_read64(cbuf, cptr); + fwrite(cbuf, 8, 1, fp); +} + +/* Implement the grid in ascii art... This makes a bit of sense if you stand + on a point over the north pole and look down on the earth. + +-180 -90 0 90 180 +------------------------------------ /\ +| 0x03 U|S 0x02 U|k 0x00 | 0x01 | 90 +|--------|--------|--------|--------| 0 +| 0x07 | 0x06 | 0x04 | 0x05 | -90 +------------------------------------ \/ +*/ +static +char grid_byte(double lat, double lon) +{ + char c = 0x00; + + if ((lon >= 0.0) && (lon < 90.0)) { + if (lat >= 0.0) { + c = 0x00; + } else { + c = 0x04; + } + } else + if (lon >= 90.0) { + if (lat >= 0.0) { + c = 0x01; + } else { + c = 0x05; + } + } else + if ((lon < 0.0) && (lon >= -90.0)) { + if (lat >= 0.0) { + c = 0x02; + } else { + c = 0x06; + } + } else + if (lon < -90.0) { + if (lat >= 0.0) { + c = 0x03; + } else { + c = 0x07; + } + } + + return (c); +} + +void decode_psp_coordinates(double * lat, double * lon, const char lonbyte) +{ + /* This is some sort of 1/2 Polar, 1/2 Cartesian coordinate mess in */ + /* the pin file. I really shouldn't have to do this. Zones 02 and 03 */ + /* work properly. The other zones are assumptions based on 02 and 03 */ + + if ((lonbyte == 0x02) || (lonbyte == 0x06)) { + /* one step west of zero longitude */ + if (*lon > 0.0) + *lon *= -1.0; + } else + if ((lonbyte == 0x03) || (lonbyte == 0x07)) { + /* two steps west of zero longitude */ + if (*lon > 0.0) + *lon -= 180.0; + } else + if ((lonbyte == 0x00) || (lonbyte == 0x04)) { + /* one step east of zero longitude */ + if (*lon < 0.0) + *lon *= -1.0; + } else + if ((lonbyte == 0x01) || (lonbyte == 0x05)) { + /* two steps east of zero longitude */ + if (*lon < 0.0) + *lon += 180.0; + } +} + +static int +valid_psp_header(char * header) +{ + char header_bytes[] = { 0x31, 0x6E, 0x69, 0x50 }; /* 1niP */ + + return (memcmp(header_bytes, header, 4)); + +} + +static char * +buffer_washer(char * buff, int buffer_len) +{ + int i; + + for (i = 0 ; i < buffer_len - 1; i++) { + if (buff[i] == '\0') { + memcpy(&buff[i], &buff[i+1], buffer_len - i); + buffer_len--; + buff[buffer_len] = '\0'; + } + } + + return (buff); +} + +static void +psp_rd_init(const char *fname) +{ + psp_file_in = xfopen(fname, "rb", MYNAME); +} + +static void +psp_rd_deinit(void) +{ + fclose(psp_file_in); +} + +static void +psp_wr_init(const char *fname) +{ + psp_file_out = xfopen(fname, "wb", MYNAME); + mkshort_handle = mkshort_new_handle(); +} + +static void +psp_wr_deinit(void) +{ + mkshort_del_handle(mkshort_handle); + fclose(psp_file_out); +} + +static void +psp_read(void) +{ + char buff[MAXPSPSTRINGSIZE + 1]; + double radians; + double lat, lon; + waypoint *wpt_tmp; + int stringsize; + short int pincount; + short int pindex; + char gridbyte = 0x00; + + /* 32 bytes - file header */ + psp_fread(&buff[0], 1, 32, psp_file_in); + + if (valid_psp_header(buff) != 0) { + fatal(MYNAME ": input file does not appear to be a valid .PSP file.\n"); + } + + pincount = le_read16(&buff[12]); + + while (pincount--) { + wpt_tmp = xcalloc(sizeof(*wpt_tmp),1); + + wpt_tmp->altitude = unknown_alt; + + /* offset 0x20 - 0x21 pin index */ + psp_fread(&pindex, 1, 2, psp_file_in); + + /* offset 0x22 - 0x23 */ + psp_fread(&buff[0], 1, 2, psp_file_in); + + /* offset 0x24 */ + /* 1 byte, the grid byte - needed for sign corrections later*/ + psp_fread(&gridbyte, 1, 1, psp_file_in); + + /* 8 bytes - latitude in radians */ + radians = psp_fread_double(psp_file_in); + lat = (radians * 180.0) / M_PI; + + /* 8 bytes - longitude in radians */ + radians = psp_fread_double(psp_file_in); + lon = (radians * 180.0) / M_PI; + + /* since we don't know the origin of this PSP file, we use */ + /* the grid byte adjust longitude, if necessary, mimicing */ + /* the behavior of pocketstreets correcting the data. This */ + /* does not correct the fact that points in eastern US are */ + /* written with the wrong coordinates by S&T. (MS bug) */ + + decode_psp_coordinates(&lat, &lon, gridbyte); + + wpt_tmp->latitude = lat; + wpt_tmp->longitude = lon; + + /* 1 byte - pin display properties */ + psp_fread(&buff[0], 1, 1, psp_file_in); + + /* 3 bytes - unknown */ + psp_fread(&buff[0], 1, 3, psp_file_in); + + /* 1 bytes - icon (values: 0x00 - 0x27) */ + psp_fread(&buff[0], 1, 1, psp_file_in); + + /* 3 bytes - unknown */ + psp_fread(&buff[0], 1, 3, psp_file_in); + + /* 1 byte - string size */ + psp_fread(&buff[0], 1, 1, psp_file_in); + + stringsize = buff[0]; + stringsize *= 2; + + if (stringsize > MAXPSPSTRINGSIZE) { + fatal(MYNAME ": variable string size (%d) in PSP file exceeds MAX (%d).\n", stringsize, MAXPSPSTRINGSIZE); + } + + /* stringsize bytes - string data */ + psp_fread(&buff[0], 1, stringsize, psp_file_in); + + buffer_washer(buff, stringsize); + + wpt_tmp->shortname = xstrdup(buff); + + /* 1 bytes string size */ + psp_fread(&buff[0], 1, 1, psp_file_in); + + stringsize = buff[0]; + stringsize *= 2; + + if (stringsize > MAXPSPSTRINGSIZE) { + fatal(MYNAME ": variable string size (%d) in PSP file exceeds MAX (%d).\n", stringsize, MAXPSPSTRINGSIZE); + } + + /* stringsize bytes - string data */ + psp_fread(&buff[0], 1, stringsize, psp_file_in); + + buffer_washer(buff, stringsize); + + wpt_tmp->description = xstrdup(buff); + + /* 1 bytes - string size */ + psp_fread(&buff[0], 1, 1, psp_file_in); + + stringsize = buff[0]; + stringsize *= 2; + + if (stringsize > MAXPSPSTRINGSIZE) { + fatal(MYNAME ": variable string size (%d) in PSP file exceeds MAX (%d).\n", stringsize, MAXPSPSTRINGSIZE); + } + + /* stringsize bytes - string data (address?) */ + psp_fread(&buff[0], 1, stringsize, psp_file_in); + + buffer_washer(buff, stringsize); + + waypt_add(wpt_tmp); + } +} + +static void +psp_waypt_pr(const waypoint *wpt) +{ + double lon, lat; + char tbuf[64]; + char c; + int i; + static short int pindex = 0; + char *shortname; + char *description; + + if ((! wpt->shortname) || (global_opts.synthesize_shortnames)) { + if (wpt->description) { + if (global_opts.synthesize_shortnames) + shortname = mkshort(mkshort_handle, wpt->description); + else + shortname = xstrdup(wpt->description); + } else { + /* no description available */ + shortname = xstrdup(""); + } + } else{ + shortname = xstrdup(wpt->shortname); + } + + if (! wpt->description) { + if (shortname) { + description = xstrdup(shortname); + } else { + description = xstrdup(""); + } + } else{ + description = xstrdup(wpt->description); + } + + /* convert lat/long back to radians */ + lat = (wpt->latitude * M_PI) / 180.0; + lon = (wpt->longitude * M_PI) / 180.0; + + pindex++; + le_write16(tbuf, pindex); + /* 2 bytes - pin index */ + fwrite(tbuf, 1, 2, psp_file_out); + + /* 2 bytes - null bytes */ + memset(tbuf, '\0', sizeof(tbuf)); + fwrite(tbuf, 1, 2, psp_file_out); + + + /* set the grid byte */ + c = grid_byte(wpt->latitude, + wpt->longitude); + + /* since the grid byte matches with what pocketstreets does to */ + /* input files, our output appears identical to a pin file that */ + /* has already been processed and corrected by pocketstreets. */ + /* Due to the grid and signs, it'll look different than one that */ + /* comes straight from S&T. */ + + /* the grid byte */ + fwrite(&c, 1, 1, psp_file_out); + + /* 8 bytes - latitude/radians */ + psp_fwrite_double(lat, psp_file_out); + + /* 8 bytes - longitude/radians */ + psp_fwrite_double(lon, psp_file_out); + + /* 1 byte - pin properties */ + c = 0x14; /* display pin name on, display notes on. 0x04 = no notes */ + fwrite(&c, 1, 1, psp_file_out); + + memset(tbuf, '\0', sizeof(tbuf)); + + /* 3 unknown bytes */ + fwrite(tbuf, 1, 3, psp_file_out); + + /* 1 icon byte 0x00 = PIN */ + fwrite(tbuf, 1, 1, psp_file_out); + + /* 3 unknown bytes */ + fwrite(tbuf, 1, 3, psp_file_out); /* 3 junk */ + + c = strlen(shortname); + /* 1 string size */ + fwrite(&c, 1, 1, psp_file_out); + + for (i = 0 ; shortname[i] ; i++) { + fwrite(&shortname[i], 1, 1, psp_file_out); /* char */ + fwrite(&tbuf[0], 1, 1, psp_file_out); /* null */ + } + + c = strlen(description); + /* 1 byte string size */ + fwrite(&c, 1, 1, psp_file_out); + + for (i = 0 ; description[i] ; i++) { + fwrite(&description[i], 1, 1, psp_file_out); /* char */ + fwrite(&tbuf[0], 1, 1, psp_file_out); /* null */ + } + + /* just for the hell of it, we'll scrap the third string. */ + c = strlen(tbuf); + /* 1 byte string size */ + fwrite(&c, 1, 1, psp_file_out); + + for (i = 0 ; tbuf[i] ; i++) { + fwrite(&tbuf[i], 1, 1, psp_file_out); /* char */ + fwrite(&tbuf[0], 1, 1, psp_file_out); /* null */ + } + + xfree(shortname); + xfree(description); +} + +static void +psp_write(void) +{ + short int s; + unsigned char header_bytes[] = { 0x31, 0x6E, 0x69, 0x50, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + /* the header: */ + /* 31 6E 69 50 20 00 00 00 08 00 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ + /* offset 0x0C - 0x0D = 2 byte pin count */ + + s = waypt_count(); + + if (global_opts.synthesize_shortnames) { + setshort_length(mkshort_handle, 32); + setshort_whitespace_ok(mkshort_handle, 1); + } + + if (s > MAXPSPOUTPUTPINS) { + fatal(MYNAME ": attempt to output too many pushpins (%d). The max is %d. Sorry.\n", s, MAXPSPOUTPUTPINS); + } + + /* insert waypoint count into header */ + le_write16(&header_bytes[12], s); + + fwrite(header_bytes, 1, 32, psp_file_out); + + waypt_disp_all(psp_waypt_pr); +} + +ff_vecs_t psp_vecs = { + ff_type_file, + psp_rd_init, + psp_wr_init, + psp_rd_deinit, + psp_wr_deinit, + psp_read, + psp_write, + NULL +}; diff --git a/queue.c b/queue.c new file mode 100644 index 000000000..db3c56e6e --- /dev/null +++ b/queue.c @@ -0,0 +1,42 @@ +/* + Generic queue utilities. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "queue.h" + +void +enqueue(queue *new_el, queue *old) +{ + new_el->next = old->next; + new_el->prev = old; + old->next->prev = new_el; + old->next = new_el; +} + +queue * +dequeue(queue *element) +{ + queue *prev = element->prev; + queue *next = element->next; + + next->prev = prev; + prev->next = next; + return element; +} diff --git a/queue.h b/queue.h new file mode 100644 index 000000000..2cbb72748 --- /dev/null +++ b/queue.h @@ -0,0 +1,51 @@ +/* + Generic queueing utilities. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +typedef struct queue { + struct queue *next; + struct queue *prev; +} queue; + +void enqueue(queue *new_el, queue *old); +queue * dequeue(queue *element); + +#define QUEUE_INIT(head) (head)->next = (head)->prev = head +#define QUEUE_FIRST(head) (head)->next +#define QUEUE_NEXT(element) (element)->next +#define QUEUE_LAST(head) (head)->prev +#define QUEUE_EMPTY (head)->next == head +#define QUEUE_MOVE(newhead,oldhead) \ + (newhead)->next = (oldhead)->next; \ + (newhead)->prev = (oldhead)->prev; \ + (newhead)->next->prev = (newhead); \ + (newhead)->prev->next = (newhead); \ + (oldhead)->next = (oldhead)->prev = (oldhead) + +#define ENQUEUE_TAIL(listhead, element) \ + enqueue(element, (listhead)->prev) +#define ENQUEUE_HEAD(listhead, element) \ + enqueue(element, listhead) + +#define QUEUE_FOR_EACH(listhead, element, tmp) \ + for ((element) = QUEUE_FIRST(listhead); \ + (tmp) = QUEUE_NEXT(element), \ + (element) != (listhead); \ + (element) = (tmp)) diff --git a/quovadis.c b/quovadis.c new file mode 100644 index 000000000..a5274f801 --- /dev/null +++ b/quovadis.c @@ -0,0 +1,296 @@ +/* + Read and write QuoVadis files. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "quovadis.h" + +static FILE *file_in; +static FILE *file_out; +static const char *out_fname; +struct pdb *opdb; + +static int ct; +static ubyte* rec_ptr = NULL; +static ubyte* current_rec = NULL; +static int rec_index = 0; + +static char *dbname = NULL; + +static +arglist_t quovadis_args[] = { + {"dbname", &dbname, "Database name", NULL, ARGTYPE_STRING}, + {0, 0, 0, 0, 0} +}; + +static struct qv_icon_mapping mapping[] = { + { gt_unknown, QUESTION_ICON }, + { gt_traditional, HOSPITAL_ICON }, + { gt_multi, DOCUMENT_ICON }, + { gt_virtual, CAMERA_ICON }, + { gt_letterbox, MAILBOX_ICON }, + { gt_event, MEETING_ICON }, + { gt_suprise, GIFTSHOP_ICON }, +}; + +#define num_mappings (sizeof(mapping) / sizeof(struct qv_icon_mapping)) + +static geocache_type icon_to_wpt(int icon_bitmap) { + unsigned int i; + + for (i = 0; i < num_mappings; i++) { + if (icon_bitmap == mapping[i].bitmap_id) { + return mapping[i].gc_type; + } + } + return gt_unknown; +} + +static int wpt_to_icon(geocache_type type) { + unsigned int i; + + for (i = 0; i < num_mappings; i++) { + if (type == mapping[i].gc_type) { + return mapping[i].bitmap_id; + } + } + return QUESTION_ICON; +} + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "rb", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); + if ( dbname ) { + xfree(dbname); + dbname = NULL; + } +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "wb", MYNAME); + out_fname = fname; +} + +static void +wr_deinit(void) +{ + fclose(file_out); + if ( dbname ) { + xfree(dbname); + dbname = NULL; + } +} + +static void +data_read(void) +{ + struct record *rec; + struct pdb *pdb; + struct pdb_record *pdb_rec; + int i; + + if (NULL == (pdb = pdb_Read(fileno(file_in)))) { + fatal(MYNAME ": pdb_Read failed\n"); + } + + if ((pdb->creator != MYCREATOR) || (pdb->type != MYTYPE)) { + fatal(MYNAME ": Not a QuoVadis file.\n"); + } + + /* Ignore the first record, it contains one zero byte */ + for(pdb_rec = pdb->rec_index.rec->next; pdb_rec; pdb_rec=pdb_rec->next) { + int num_recs = pdb_rec->data_len / sizeof(struct record); + for (i = 0; i < num_recs; i++) { + waypoint *wpt_tmp; + + wpt_tmp = waypt_new(); + + rec = (struct record *) + &(pdb_rec->data[i * sizeof(struct record)]); + + wpt_tmp->longitude = + (be_read32(&rec->longitude) / 1000000.0) - 180.0; + wpt_tmp->latitude = + 90.0 - (be_read32(&rec->latitude) / 1000000.0); + wpt_tmp->shortname = xstrdup(rec->name); + + wpt_tmp->gc_data.type = + icon_to_wpt(be_read16(&rec->icon_bitmap)); + + waypt_add(wpt_tmp); + } + } + free_pdb(pdb); +} + + +static void +quovadis_writewpt(waypoint *wpt) +{ + struct record *rec; + int i; + + if (current_rec == NULL) { + ubyte dummy = 0; + struct pdb_record *pdb_rec; + pdb_rec = new_Record(0, 0, ct++, 1, &dummy); + if (pdb_rec == NULL) { + fatal(MYNAME ": libpdb couldn't create record\n"); + } + if (pdb_AppendRecord(opdb, pdb_rec)) { + fatal(MYNAME ": libpdb couldn't append record\n"); + } + + current_rec = (ubyte *) xcalloc(MAXCHUNKSIZE, 1); + rec_index = 0; + rec_ptr = current_rec; + } + + rec = (struct record *) xcalloc(sizeof(*rec),1); + + be_write32(&rec->longitude, (wpt->longitude + + 180.0) * 1000000.0); + be_write32(&rec->latitude, (90.0 - wpt->latitude) * 1000000.0); + if ( wpt->shortname ) { + strncpy(rec->name, wpt->shortname, 32 ); + rec->name[31] = '\0'; + } + else { + rec->name[0] = '\0'; + } + be_write16(&rec->icon_bitmap, wpt_to_icon(wpt->gc_data.type)); + be_write32(&rec->note_id, 0); + rec->name_scale = DEFAULT_NAME_SCALE; + rec->icon_scale = DEFAULT_ICON_SCALE; + for (i = 0; i < 7; i++) { + rec->reserved[i] = 0; + } + + memcpy(rec_ptr, rec, sizeof(*rec)); + rec_ptr += sizeof(*rec); + rec_index += 1; + xfree(rec); + + if (rec_index == MAXRECORDS) { + fatal(MYNAME ": cannot store more than %d records at this time.\n", + MAXRECORDS); + } +} + +struct hdr{ + char *wpt_name; + waypoint *wpt; +}; + +static +int +compare(const void *a, const void *b) +{ + const struct hdr *wa = (const struct hdr *) a; + const struct hdr *wb = (const struct hdr *) b; + + return strcmp(wa->wpt->shortname, wb->wpt->shortname); +} + +static void +data_write(void) +{ + int i, ct = waypt_count(); + struct hdr *htable, *bh; + queue *elem, *tmp; + extern queue waypt_head; + waypoint *waypointp; + + if (NULL == (opdb = new_pdb())) { + fatal (MYNAME ": new_pdb failed\n"); + } + + if ( dbname ) { + strncpy( opdb->name, dbname, PDB_DBNAMELEN ); + } + else { + strncpy(opdb->name, "QuoVadisMarkerDB", PDB_DBNAMELEN); + } + opdb->name[PDB_DBNAMELEN-1] = 0; + opdb->attributes = PDB_ATTR_BACKUP; + opdb->ctime = opdb->mtime = current_time() + 2082844800U; + opdb->type = MYTYPE; /* CWpt */ + opdb->creator = MYCREATOR; /* cGPS */ + opdb->version = 1; + + /* + * All this is to sort by waypoint names before going to QuoVadis. + * Turns out plain old strcmp will do the trick... + */ + + htable = (struct hdr *) xmalloc(ct * sizeof(*htable)); + bh = htable; + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + waypointp = (waypoint *) elem; + bh->wpt = waypointp; + bh->wpt_name = waypointp->shortname; + bh ++; + } + qsort(htable, ct, sizeof(*bh), compare); + + for (i=0;i + 18.12 miles, 26 => 46 feet */ + char icon_scale; /* As above. */ + unsigned char reserved[8]; +}; + +struct qv_icon_mapping { + const geocache_type gc_type; + const int bitmap_id; +}; + +/* Icon Types */ +#define QUESTION_ICON 0 +#define RESTARAUNT_ICON 1 +#define BAR_ICON 2 +#define HOTEL_ICON 3 +#define PHONE_ICON 4 +#define HOSPITAL_ICON 5 +#define CHURCH_ICON 6 +#define AIRPORT_ICON 7 +#define TRAIN_ICON 8 +#define BUS_ICON 9 +#define CAR_ICON 10 +#define WRENCH_ICON 11 +#define GASOLINE_ICON 12 +#define PARKING_ICON 13 +#define MAIL_ICON 14 +#define MAILBOX_ICON 15 +#define CLOCK_ICON 16 +#define FLAG_ICON 17 +#define LIBRARY_ICON 18 +#define BUILDINGS_ICON 19 +#define RELIGION_ICON 20 +#define DOCUMENT_ICON 21 +#define ANIMAL_ICON 22 +#define CAMERA_ICON 23 +#define MOVIE_ICON 24 +#define MUSIC_ICON 25 +#define MEETING_ICON 26 +#define RESTROOM_ICON 27 +#define FAMILY_ICON 28 +#define TELEVISION_ICON 29 +#define SAILING_ICON 30 +#define GOLF_ICON 31 +#define WORKOUT_ICON 32 +#define CYCLING_ICON 33 +#define JOGGING_ICON 34 +#define CAMPING_ICON 35 +#define WATER_ICON 36 +#define FOREST_ICON 37 +#define GIFTSHOP_ICON 38 +#define BABY_ICON 39 +#define LOVE_ICON 40 +#define CEMETARY_ICON 41 +#define COMPUTER_ICON 42 +#define MONEY_ICON 43 +#define LEFT_ARROW_ICON 44 +#define RIGHT_ARROW_ICON 45 +#define DOWN_ARROW_ICON 46 +#define UP_ARROW_ICON 47 + +/* Scale Values */ +#define SCALE_18_12MI 15 +#define SCALE_9_06MI 16 +#define SCALE_4_53MI 17 +#define SCALE_2_26MI 18 +#define SCALE_1_13MI 19 +#define SCALE_0_56MI 20 +#define SCALE_0_28MU 21 +#define SCALE_747FT 22 +#define SCALE_373FT 23 +#define SCALE_186FT 24 +#define SCALE_93FT 25 +#define SCALE_46FT 26 + +#define MAXRECORDS (MAXCHUNKSIZE / sizeof(struct record)) +/*#define MAXRECORDS 100*/ +#define DEFAULT_ICON_BITMAP QUESTION_ICON +#define DEFAULT_NAME_SCALE SCALE_2_26MI +#define DEFAULT_ICON_SCALE SCALE_18_12MI + +#endif diff --git a/reference/GeocachingDB.PDB b/reference/GeocachingDB.PDB new file mode 100644 index 0000000000000000000000000000000000000000..4f6c38b6ba2ec34822bf548f5317cfdc146d595d GIT binary patch literal 5822 zcmeHL%TC)s6urF4qm{a7)g_v4T99C{XZ(oOhvb+fg_eLqppQ*8Nemc_Eg1(IRCV1S z=)T`ksZv)}KdOt~aU2|~AhpFv70L*6CSzliGv}PSGZi;%isqgd>@F8!P@960FPmRK z$?Nyq%XZx^Mj}2NpTXYe(d6SufH(p$`VkR-#(v6Q02AL3#{njPAWi_x+(WzpaO*qb zB*1NnQvi2n5vTE0GrP?|AU@h{dM(6BU&IRHD58ouhR6_S{4nT_hk+a)$Io*7X3N{z zL7a}=D3VxRd9_}BxJl~IN@TrSx=$J%@}a)xl2y?;S|IgEw7l301K|?~nQ_USO7$hY z<^d`W<4zf%3fuzFRm!<)6%=?0i>3~X8lwg`z2 zv$@i81usjPF6PCwlw3Uuk6j{Sf;I|Tof9u`|3Z$aMoTroN;xl3OIIbusT#RPnUTm7 znNHQHupax8p}8xd>A!wu-g8)V#jzWa)HG<6noJCTfz-U_0eL`{@%F$-VHhcR&10f) zt!($^P**5tyx%vR>UuJOGndU_FI$jonQ_B*2?kP47C_!1Nh z|MUtNNOeV1UER2B-QpF4c0=l@X=BE`4c-U)VsN%BF{vlUdACks8mA^EMy4iB$JJPo zF~hU^<*sYvVtk1*HKM?Uip`zltb+uV> zjG|_zb+x8z)Jih$tdhYenJ)F(SIL~y>&A7StKoOcpMkvfUlOMsvex!vZ&B{2lQMqI zjm2q0w6G9d^$rg^$&H2dsdR72WLTsAHPyylYqI)lxQ#5Zb9v3FqA?lZS^eJELw4Te z&(QFVLk9kwfz(f>yw;PgBX_6mla<&#Jjzy+3mi4z%qH;_RzbSToV2QD=qs~pquzN9 z`btTv>OMDR6%l@WdEzu|Lk6x51F27+=H=7UyEqd6Y|zA?y}Hkl$EV#x!pxrr?t1Y^ Li=Mf%uLtl8M3dT< literal 0 HcmV?d00001 diff --git a/reference/Glad_4.exp b/reference/Glad_4.exp new file mode 100644 index 0000000000000000000000000000000000000000..17d1fc56bdfb35a9eb2e00f74f43b47842348fce GIT binary patch literal 19994 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 XdQ6Lv{?#xtjOZ~THX^ZeZfyJ?B-RD% literal 0 HcmV?d00001 diff --git a/reference/Glad_5.exp b/reference/Glad_5.exp new file mode 100644 index 000000000..458090147 --- /dev/null +++ b/reference/Glad_5.exp @@ -0,0 +1,536 @@ + + + + 1.0000000 + ROUTENAME + 0 + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMEdward Islandlegnum0usrmrkEdward Islandselect2 + attr=grpnamROUTENAME + 1 + -20.226667 + 149.205000 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMScawfell Islandlegnum1usrmrkScawfell Islandselect2 + attr=grpnamROUTENAME + 1 + -20.850001 + 149.641668 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMMiddle Islandlegnum2usrmrkMiddle Islandselect2 + attr=grpnamROUTENAME + 1 + -21.680097 + 150.176053 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMClara Grouplegnum3usrmrkClara Groupselect2 + attr=grpnamROUTENAME + 1 + -22.318424 + 150.747717 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMCape Capricornlegnum4usrmrkCape Capricornselect2 + attr=grpnamROUTENAME + 1 + -23.448418 + 151.322717 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGladstone FWBlegnum5usrmrkGladstone FWBselect2 + attr=grpnamROUTENAME + 1 + -23.890915 + 151.516051 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMHigh Peaklegnum6usrmrkHigh Peakselect2 + attr=grpnamROUTENAME + 1 + -21.951660 + 150.754997 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMPenrith Islandlegnum7usrmrkPenrith Islandselect2 + attr=grpnamROUTENAME + 1 + -20.988435 + 149.929386 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMPinnacle Pointlegnum8usrmrkPinnacle Pointselect2 + attr=grpnamROUTENAME + 1 + -20.081094 + 149.064391 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMTink Shoallegnum9usrmrkTink Shoalselect2 + attr=grpnamROUTENAME + 1 + -19.375083 + 147.819368 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMPeloruslegnum10usrmrkPelorusselect2 + attr=grpnamROUTENAME + 1 + -18.433464 + 146.549414 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMEva Islandlegnum11usrmrkEva Islandselect2 + attr=grpnamROUTENAME + 1 + -18.213466 + 146.409415 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMLittle Fitzroy Islandlegnum12usrmrkLittle Fitzroy Islandselect2 + attr=grpnamROUTENAME + 1 + -16.913473 + 146.059411 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMCairns FWBlegnum13usrmrkCairns FWBselect2 + attr=grpnamROUTENAME + 1 + -16.731976 + 145.889412 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMLow Isleslegnum14usrmrkLow Islesselect2 + attr=grpnamROUTENAME + 1 + -16.465145 + 145.637746 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMPickersgill Reeflegnum15usrmrkPickersgill Reefselect2 + attr=grpnamROUTENAME + 1 + -15.921815 + 145.481079 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGubbinslegnum16usrmrkGubbinsselect2 + attr=grpnamROUTENAME + 1 + -15.708467 + 145.382747 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMThree Isleslegnum17usrmrkThree Islesselect2 + attr=grpnamROUTENAME + 1 + -15.110153 + 145.402742 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMPalfreylegnum18usrmrkPalfreyselect2 + attr=grpnamROUTENAME + 1 + -14.673488 + 145.417741 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMNymph Islandlegnum19usrmrkNymph Islandselect2 + attr=grpnamROUTENAME + 1 + -14.626822 + 145.251076 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMCoquetlegnum20usrmrkCoquetselect2 + attr=grpnamROUTENAME + 1 + -14.546824 + 145.061078 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMHowicklegnum21usrmrkHowickselect2 + attr=grpnamROUTENAME + 1 + -14.483492 + 144.979412 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMMegaeralegnum22usrmrkMegaeraselect2 + attr=grpnamROUTENAME + 1 + -14.483492 + 144.932746 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMWatsonlegnum23usrmrkWatsonselect2 + attr=grpnamROUTENAME + 1 + -14.451826 + 144.902746 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMBarrowlegnum24usrmrkBarrowselect2 + attr=grpnamROUTENAME + 1 + -14.361826 + 144.686082 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMRocky Pointlegnum25usrmrkRocky Pointselect2 + attr=grpnamROUTENAME + 1 + -14.195161 + 144.604414 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMPiponlegnum26usrmrkPiponselect2 + attr=grpnamROUTENAME + 1 + -14.138495 + 144.511082 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMKing Islandlegnum27usrmrkKing Islandselect2 + attr=grpnamROUTENAME + 1 + -14.060164 + 144.331084 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMClack Islandlegnum28usrmrkClack Islandselect2 + attr=grpnamROUTENAME + 1 + -14.101829 + 144.244418 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMWharton Reeflegnum29usrmrkWharton Reefselect2 + attr=grpnamROUTENAME + 1 + -14.101831 + 143.977755 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMEdenlegnum30usrmrkEdenselect2 + attr=grpnamROUTENAME + 1 + -14.065165 + 143.917756 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMStainer Reeflegnum31usrmrkStainer Reefselect2 + attr=grpnamROUTENAME + 1 + -13.981832 + 143.834422 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMPelicanlegnum32usrmrkPelicanselect2 + attr=grpnamROUTENAME + 1 + -13.915167 + 143.812756 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMMagpielegnum33usrmrkMagpieselect2 + attr=grpnamROUTENAME + 1 + -13.815167 + 143.734423 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMFifelegnum34usrmrkFifeselect2 + attr=grpnamROUTENAME + 1 + -13.656835 + 143.704422 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMHeath Reeflegnum35usrmrkHeath Reefselect2 + attr=grpnamROUTENAME + 1 + -13.475170 + 143.671089 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMBow Reeflegnum36usrmrkBow Reefselect2 + attr=grpnamROUTENAME + 1 + -13.341836 + 143.671089 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMOsbornelegnum37usrmrkOsborneselect2 + attr=grpnamROUTENAME + 1 + -13.096838 + 143.611087 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMChapmanlegnum38usrmrkChapmanselect2 + attr=grpnamROUTENAME + 1 + -12.886839 + 143.594420 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMWye Reeflegnum39usrmrkWye Reefselect2 + attr=grpnamROUTENAME + 1 + -12.818506 + 143.586087 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMEel Reeflegnum40usrmrkEel Reefselect2 + attr=grpnamROUTENAME + 1 + -12.415159 + 143.362754 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMPiperlegnum41usrmrkPiperselect2 + attr=grpnamROUTENAME + 1 + -12.236844 + 143.247755 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMMoodylegnum42usrmrkMoodyselect2 + attr=grpnamROUTENAME + 1 + -12.085178 + 143.239421 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMClerkelegnum43usrmrkClerkeselect2 + attr=grpnamROUTENAME + 1 + -11.963513 + 143.317754 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMHanniballegnum44usrmrkHannibalselect2 + attr=grpnamROUTENAME + 1 + -11.586850 + 142.981089 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMHalfwaylegnum45usrmrkHalfwayselect2 + attr=grpnamROUTENAME + 1 + -11.378517 + 142.986088 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMCairncrosslegnum46usrmrkCairncrossselect2 + attr=grpnamROUTENAME + 1 + -11.231851 + 142.954422 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMWybornlegnum47usrmrkWybornselect2 + attr=grpnamROUTENAME + 1 + -10.806855 + 142.804421 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMAlbany Rocklegnum48usrmrkAlbany Rockselect2 + attr=grpnamROUTENAME + 1 + -10.741856 + 142.676089 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMAlpha Rocklegnum49usrmrkAlpha Rockselect2 + attr=grpnamROUTENAME + 1 + -10.601857 + 142.552756 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMHerald Patcheslegnum50usrmrkHerald Patchesselect2 + attr=grpnamROUTENAME + 1 + -10.501859 + 142.377759 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMEast Strait Leadslegnum51usrmrkEast Strait Leadsselect2 + attr=grpnamROUTENAME + 1 + -10.480192 + 142.334426 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMShadwell Pointlegnum52usrmrkShadwell Pointselect2 + attr=grpnamROUTENAME + 1 + -10.495193 + 142.282760 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMNardanalegnum53usrmrkNardanaselect2 + attr=grpnamROUTENAME + 1 + -10.508525 + 142.251094 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMHammondlegnum54usrmrkHammondselect2 + attr=grpnamROUTENAME + 1 + -10.510193 + 142.202761 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMHarrisonlegnum55usrmrkHarrisonselect2 + attr=grpnamROUTENAME + 1 + -10.561860 + 142.126094 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMB1legnum56usrmrkB1select2 + attr=grpnamROUTENAME + 1 + -10.568518 + 141.909434 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMRed Bankslegnum57usrmrkRed Banksselect2 + attr=grpnamROUTENAME + 1 + -10.829183 + 141.659174 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMDuyfken Ptlegnum58usrmrkDuyfken Ptselect2 + attr=grpnamROUTENAME + 1 + -12.568516 + 141.501109 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMWeipa Leadslegnum59usrmrkWeipa Leadsselect2 + attr=grpnamROUTENAME + 1 + -12.705000 + 141.661667 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMWeipa FWBlegnum60usrmrkWeipa FWBselect2 + attr=grpnamROUTENAME + 1 + -12.700000 + 141.688333 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGannetlegnum61usrmrkGannetselect2 + attr=grpnamROUTENAME + 1 + -10.590757 + 141.875120 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMB2legnum62usrmrkB2select2 + attr=grpnamROUTENAME + 1 + -10.575158 + 141.891066 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMMid Decaplegnum63usrmrkMid Decapselect2 + attr=grpnamROUTENAME + 1 + -14.965864 + 145.407427 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMTurtlelegnum64usrmrkTurtleselect2 + attr=grpnamROUTENAME + 1 + -14.632647 + 145.189251 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMNewtonlegnum65usrmrkNewtonselect2 + attr=grpnamROUTENAME + 1 + -14.517176 + 144.911975 + + + diff --git a/reference/UKultralight.pdb b/reference/UKultralight.pdb new file mode 100644 index 0000000000000000000000000000000000000000..9112b55a8bd3205784c60da7df8d1b59cd41ad93 GIT binary patch literal 26248 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 literal 0 HcmV?d00001 diff --git a/reference/arcdist_arc.txt b/reference/arcdist_arc.txt new file mode 100644 index 000000000..c79e1866f --- /dev/null +++ b/reference/arcdist_arc.txt @@ -0,0 +1,115 @@ +41.150064468 -85.166207433 +41.150064468 -85.165371895 +41.149034500 -85.165157318 +41.147832870 -85.164771080 +41.146631241 -85.164384842 +41.144270897 -85.163655281 +41.141953468 -85.162882805 +41.139550209 -85.162281990 +41.137833595 -85.161852837 +41.136546135 -85.161681175 +41.132812500 -85.160608292 +41.132340431 -85.160479546 +41.131739616 -85.160050392 +41.131138802 -85.159664154 +41.130237579 -85.158977509 +41.129765511 -85.158634186 +41.129636765 -85.158548355 +41.129379272 -85.158419609 +41.129207611 -85.158333778 +41.128950119 -85.158162117 +41.128821373 -85.158033371 +41.128478050 -85.157775879 +41.126074791 -85.155844688 +41.125044823 -85.154857635 +41.122341156 -85.152668953 +41.119766235 -85.150566101 +41.118135452 -85.149278641 +41.117362976 -85.148591995 +41.114530563 -85.146059990 +41.112856865 -85.144772530 +41.112256050 -85.144085884 +41.111955643 -85.143871307 +41.110539436 -85.142970085 +41.108264923 -85.141167641 +41.107234955 -85.140352249 +41.106162071 -85.139665604 +41.105132103 -85.138678551 +41.104745865 -85.138163567 +41.104145050 -85.138163567 +41.103029251 -85.138163567 +41.102042198 -85.138077736 +41.101140976 -85.138077736 +41.099338531 -85.137948990 +41.099038124 -85.137948990 +41.098566055 -85.137391090 +41.096849442 -85.136961937 +41.096334457 -85.136575699 +41.094231606 -85.135588646 +41.093759537 -85.134687424 +41.093158722 -85.134387016 +41.092128754 -85.134258270 +41.091527939 -85.134172440 +41.091141701 -85.134172440 +41.090455055 -85.134172440 +41.089339256 -85.134172440 +41.088523865 -85.134301186 +41.088137627 -85.134387016 +41.087751389 -85.134558678 +41.086850166 -85.135159492 +41.085863113 -85.135459900 +41.084446907 -85.135760307 +41.083846092 -85.135459900 +41.083159447 -85.135374069 +41.082558632 -85.135159492 +41.082043648 -85.135073662 +41.081056595 -85.134773254 +41.079940796 -85.134472847 +41.079039574 -85.134172440 +41.077966690 -85.133872032 +41.076936722 -85.133571625 +41.075863838 -85.133271217 +41.075134277 -85.132970810 +41.075134277 -85.133271217 +41.074147224 -85.133271217 +41.073632240 -85.133271217 +41.073160172 -85.133271217 +41.071443558 -85.133271217 +41.070327759 -85.133228302 +41.069641113 -85.133185387 +41.069340706 -85.133056641 +41.068739891 -85.133056641 +41.068353653 -85.133056641 +41.067967415 -85.133013725 +41.067452431 -85.132970810 +41.066765785 -85.132884979 +41.066336632 -85.132884979 +41.065864563 -85.132884979 +41.065349579 -85.132884979 +41.064362526 -85.132884979 +41.063246727 -85.132884979 +41.062345505 -85.132756233 +41.061229706 -85.132756233 +41.060628891 -85.132756233 +41.059641838 -85.132670403 +41.058654785 -85.132584572 +41.058139801 -85.132584572 +41.057753563 -85.132541656 +41.057066917 -85.132455826 +41.056551933 -85.132455826 +41.055951118 -85.132455826 +41.055564880 -85.132455826 +41.054663658 -85.132369995 +41.053762436 -85.132284164 +41.053247452 -85.132284164 +41.052260399 -85.132284164 +41.051745415 -85.132284164 +41.050758362 -85.132155418 +41.049942970 -85.132069588 +41.049127579 -85.132069588 +41.047539711 -85.131983757 +41.046037674 -85.131855011 +41.045737267 -85.131983757 +41.045050621 -85.133056641 +41.044921875 -85.133056641 +41.044343591 -85.132979512 diff --git a/reference/arcdist_input.txt b/reference/arcdist_input.txt new file mode 100644 index 000000000..e3f361027 --- /dev/null +++ b/reference/arcdist_input.txt @@ -0,0 +1,103 @@ + +BEGIN SYMBOL +41.14703, -85.11092, N.E.R.D. by Enos Shenk Unknown Cache (3/3) +41.13940, -85.10142, Fallen Timbers by TeamMJ Traditional Cache (2/2) +41.14415, -85.14415, Historic Iron Bridges by Genoist (1/2 of TeamSJ1) Locationless (Reverse) Cache (1/1) +41.12890, -85.11163, Mastadon Trek 2 by Genoist and Dogvetusa Traditional Cache (2/2) +41.16413, -85.14688, NYC Trail by VistaAL Traditional Cache (1/1.5) +41.15900, -85.15418, Craftily Concealed Containers by Warm Fuzzies Multi-Cache (4/2) +41.12210, -85.11097, Land of Lost Auto Parts by Genoist and The Zymurgist Traditional Cache (1/5) +41.17732, -85.15117, The Farm by AParks1569 Traditional Cache (1.5/1.5) +41.10757, -85.13087, Swonderful by Genoist and The Zymurgist Traditional Cache (2/5) +41.12733, -85.06728, Dr. Mengerson I Preserve by Genoist Traditional Cache (2/2) +41.10417, -85.15167, Clue by Warm Fuzzies Multi-Cache (3.5/2) +41.10823, -85.16212, Son of Pez by Enos Shenk Traditional Cache (1.5/1.5) +41.09278, -85.14073, Urbana #3: Dodgy Deals by Enos Shenk Traditional Cache (2.5/1.5) +41.09258, -85.09258, Secret Squirrels by Enos Shenk & Panic! Unknown Cache (4/1) +41.08748, -85.13762, A King's Ransom by Team ABC and The GeoStars Team Traditional Cache (1.5/1) +41.08427, -85.13597, Urbana #4: The City She Loves Me by Enos Shenk & Athena Traditional Cache (3.5/2) +41.08582, -85.07230, Caribbean Cache by Genoist and Dogvetusa Traditional Cache (3/2) +41.08190, -85.17180, Earthling Vector Luna- 2nd Phase by Earthling and Heavenbound Traditional Cache (1/1.5) +41.08400, -85.05387, Earthling Vector Sol by Earthling & Heavenbound Traditional Cache (1.5/1.5) +41.20673, -85.03985, The Sarsaparilla Cache by Cashconnect Traditional Cache (2/1.5) +41.06353, -85.13400, Sky High by Enos Shenk Virtual Cache (1/3) +41.09880, -85.21725, We Support Our Troops by Genoist and The Zymurgist Traditional Cache (2/2.5) +41.06950, -85.19750, Shortwave by Warm Fuzzies Unknown Cache (4/2.5) +41.06255, -85.04757, Starfall by Enos Shenk Traditional Cache (2/2.5) +41.07482, -85.01957, Fly Like an Eagle by Team SJ1 Traditional Cache (2/2) +41.04714, -85.16617, Perfectly Perplexing Puzzles by Warm Fuzzies Multi-Cache (5/3.5) +41.07197, -85.01863, Arrow Haven (2/4) by Genoist Traditional Cache (2/2.5) +41.07183, -85.01850, Heat Death (3/4) by Genoist Traditional Cache (2/3) +41.06827, -85.01655, Abbadon by Genoist Traditional Cache (1.5/4) +41.01503, -85.13290, Earthling Vector Pluto by Earthling & Heavenbound Traditional Cache (1/1.5) +41.26535, -84.98950, Outstanding In Its Field Cache by kwbach Traditional Cache (2/2) +41.00470, -85.05742, Earthling Vector Perelandra by Earthling & Heavenbound Multi-Cache (4/1.5) +41.04247, -85.27570, KWAANTINAKAANI by Northmill Jo-Jo Beans and E-Bone Letterbox Hybrid (2/1) +41.01760, -85.25190, Earthling Vector Terra by Earthling & Heavenbound Traditional Cache (1.5/2.5) +40.97610, -85.22277, 47520 Feet by kidCraZy Traditional Cache (1/1.5) +41.35740, -85.05117, A.C.D. Cache by 1MARKYMARK1 Traditional Cache (2/2.5) +41.03592, -84.80323, EV-Castor & Pollux by Starhenge Multi-Cache (1/1.5) +41.30855, -84.82960, Earthling Vector Malacandra by Earthling and Heavenbound Traditional Cache (1/1.5) +41.33727, -85.39282, One Lost Ten Found by The GeoStars Team and Team ABC Traditional Cache (3/5) +41.33552, -85.40885, The Leprechaun's Pot of Gold by Pete and Maureen Traditional Cache (1/1) +41.08543, -84.72823, Payne Train by rlong3 (Long Clan) Traditional Cache (1.5/1) +41.44473, -85.24797, Straight Flush by The GeoStars Team and Team ABC Multi-Cache (4/5) +40.89088, -85.47038, 'Clare' up There by Zig & Zag Traditional Cache (2/3) +40.82507, -85.35552, Jeanette's Journey by kidCraZy Multi-Cache (2.5/1.5) +40.84245, -85.42245, Pine Sol by Indiana Herring Traditional Cache (1.5/2) +40.84662, -85.43382, Kil--So--Quah by Good Dog Traditional Cache (1.5/2) +40.80862, -85.35608, Stuck in the middle by The Hoosier River Rats Traditional Cache (2/2.5) +40.80768, -85.36637, Rock Creek by The Hoosier River Rats Traditional Cache (2/2) +40.87892, -85.50570, Sunken Treasure by Smokey and Family Traditional Cache (2/1) +40.83560, -85.45415, Clue Two by geoprime Traditional Cache (2/3) +41.53267, -84.94377, Robb Hidden Canyon by VM's Traditional Cache (2/3) +41.53553, -84.93188, Fish Creek Trail by VM's Multi-Cache (3.5/1) +40.87942, -85.54058, All Locked Up by Zig & Zag Traditional Cache (1/1) +40.71773, -85.10702, OUABACHE CACHE by ZoneRanger Traditional Cache (1/1) +41.34498, -85.68462, Wy-Tri Cache by capt zigzag & echoes Traditional Cache (2/2) +41.54878, -85.45370, Delt Church Dino Cache by GeoStars Traditional Cache (1.5/2.5) +41.56537, -85.46163, Clearspring Cache by capt zigzag & echoes Traditional Cache (1.5/1.5) +41.56282, -85.46893, Ace-in-the-Hole by The GeoStars Team and Team ABC Multi-Cache (2/2) +41.62350, -85.33873, Geocache by Maple Wood Nature Center Traditional Cache (1/1) +41.20898, -84.45685, Aqueduct by coinhound Traditional Cache (2/1.5) +41.66538, -85.17465, Gannon Cache by capt zigzag & echoes Traditional Cache (2/1.5) +41.22390, -84.42585, 5 Mile Creek Access by coinhound Traditional Cache (1/1) +40.76567, -85.59953, Missing Dental Work by Indiana Herring Traditional Cache (2/3.5) +40.75487, -85.59022, Salamonie Reservoir Trail Cache by Indy Diver Traditional Cache (1/1.5) +40.78918, -85.65105, Dead End Cache by JollyBGood Traditional Cache (1.5/1.5) +41.34360, -84.44365, Oxbow lake AKA ( wabit twacks) by coinhound Traditional Cache (1/1.5) +40.81153, -85.68533, In 'Hominy' with nature by Zig & Zag Traditional Cache (1/2.5) +40.80997, -85.68650, Myrna's Treasure by Myrna's Mountaineers Traditional Cache (2/1) +40.82988, -85.70725, Just Hanging Around by Zig & Zag Traditional Cache (4.5/3.5) +40.63288, -85.36448, 13 graves and A Ghost by RedNeck Tracking INC. Traditional Cache (1/1) +40.61557, -84.94355, 1861 Covered Cache by RedNeck Tracking INC. Traditional Cache (2/1) +40.61378, -84.94383, Trailsend 1860 by RedNeck Tracking INC. Traditional Cache (1/1) +41.69980, -85.03385, Nature's Back Yard by Cat E Wampus Traditional Cache (2/1.5) +41.69567, -85.30143, Center Field by therealmongo Traditional Cache (2/2.5) +41.70473, -84.99397, Back to our Beloved Sport by Max's Pets with Birddog Traditional Cache (2/2) +41.69323, -85.33213, Pigion River Cache by Bonnie & Clyde Traditional Cache (2.5/2) +41.71252, -85.02377, Artesian by Good Dog Traditional Cache (1.5/1.5) +41.71708, -85.02897, P.S.P. by The Wolfe Clan Traditional Cache (1/1.5) +41.71720, -85.01957, Earthling Vector Mercury by Earthling & Heavenbound Traditional Cache (1.5/2) +41.71535, -84.98552, Marsh Lake High Ground by VirtualMoore Traditional Cache (3/2) +41.55555, -84.57783, Bible Park Stash by DwFlatP8 and Luckyfriend Traditional Cache (1.5/1.5) +41.23113, -84.36397, Taylor Made by Team WolfPack Traditional Cache (1/1.5) +41.71960, -84.96467, The Crane Waterfall by VM's Traditional Cache (2/2.5) +40.63232, -85.47248, Serenity by Indiana and Marion Traditional Cache (1.5/1) +41.24542, -84.35613, "Tanks" For The Memories by Team WolfPack Traditional Cache (1/1) +41.29958, -84.36582, Lets Make A "Diehl" by Team WolfPack Traditional Cache (1/1) +41.72573, -84.96353, 80/90 Westbound Cache by Good Dog Traditional Cache (1/1) +41.28945, -84.35925, Confluence Cache by Team WolfPack Multi-Cache (2/1) +41.71007, -85.37105, Lane Lake Cache by capt zigzag and echoes Traditional Cache (2/2) +41.69660, -84.80602, tristate marker by Hillsdale Historical Society Virtual Cache (1/1) +41.51000, -85.78042, School Daze by Lobo Valiente Virtual Cache (1/1) +41.55730, -84.50957, Cemetery Hill by DwFlatP8 and Luckyfriend Traditional Cache (1.5/1.5) +40.53373, -85.14770, Balbec Cabin Keychains by RedNeck Tracking INC. Traditional Cache (1/1) +40.93718, -84.33907, Big Green by tex4711 Traditional Cache (1.5/1) +41.38972, -85.89556, Island Cache by Bonnie & Clyde Traditional Cache (1.5/1) +41.69122, -84.67567, glacial trailing by Mark Robinette Traditional Cache (2.5/2) +40.51967, -84.98795, Liberty Cache by RedNeck Tracking INC. Traditional Cache (1/1) +41.51870, -85.81747, Five Medals by kam Traditional Cache (2/2) +41.01977, -84.28587, The Book Worm by Team Ace Traditional Cache (1/1) +41.29335, -84.28538, Bushwacker by Panther2 Traditional Cache (2/3) +END diff --git a/reference/arcdist_output.txt b/reference/arcdist_output.txt new file mode 100644 index 000000000..693773cbc --- /dev/null +++ b/reference/arcdist_output.txt @@ -0,0 +1,11 @@ +BEGIN SYMBOL +41.14415, -85.14415, Historic Iron Bridges by Genoist (1/2 of TeamSJ1) Locationless (Reverse) Cache (1/1) +41.15900, -85.15418, Craftily Concealed Containers by Warm Fuzzies Multi-Cache (4/2) +41.10757, -85.13087, Swonderful by Genoist and The Zymurgist Traditional Cache (2/5) +41.10417, -85.15167, Clue by Warm Fuzzies Multi-Cache (3.5/2) +41.10823, -85.16212, Son of Pez by Enos Shenk Traditional Cache (1.5/1.5) +41.09278, -85.14073, Urbana #3: Dodgy Deals by Enos Shenk Traditional Cache (2.5/1.5) +41.08748, -85.13762, A King's Ransom by Team ABC and The GeoStars Team Traditional Cache (1.5/1) +41.08427, -85.13597, Urbana #4: The City She Loves Me by Enos Shenk & Athena Traditional Cache (3.5/2) +41.06353, -85.13400, Sky High by Enos Shenk Virtual Cache (1/3) +END diff --git a/reference/cetus.gpu b/reference/cetus.gpu new file mode 100644 index 000000000..c701f7040 --- /dev/null +++ b/reference/cetus.gpu @@ -0,0 +1,9 @@ +GC1A37 3605.441N 08640.773W 0000000m The Troll by a182pilot & Famil a +GC1C2B 3559.776N 08637.207W 0000000m Dive Bomber by JoGPS & family a +GC25A9 3602.309N 08638.917W 0000000m FOSTER by JoGPS & Family a +GC2723 3606.731N 08644.506W 0000000m Logan Lighthouse by JoGps & Fa a +GC2B71 3603.845N 08647.431W 0000000m Ganier Cache by Susy1313 a +GC309F 3605.266N 08648.584W 0000000m Shy's Hill by FireFighterEng33 a +GC317A 3603.450N 08653.520W 0000000m GittyUp by JoGPS / Warner Park a +GC317D 3604.968N 08652.037W 0000000m Inlighting by JoGPS / Warner P a +GCEBB 3558.322N 08708.082W 0000000m Mountain Bike Heaven by susy13 a diff --git a/reference/cetus.pdb b/reference/cetus.pdb new file mode 100644 index 0000000000000000000000000000000000000000..a15ff2f51d04be3b3ceecc3a7498c04afe271057 GIT binary patch literal 1095 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%0A^M>ugv^`%+^!3~SUdCGUf=Y@$iQ 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 K|8V`IPTWu3Homa{ literal 0 HcmV?d00001 diff --git a/reference/geoniche.pdb b/reference/geoniche.pdb new file mode 100644 index 0000000000000000000000000000000000000000..0c8ba057677bb0d243b03a2e2c5c1e431a9d9726 GIT binary patch literal 1422 zcma)+&2rN)6op+VzfYkRY=kYzwq&s^O;VUP1QKA2QdC=0SI*c@XZ$woc?Fg%c?e#D z4J)paI0-+ktx0@rDRa-4qbryCLYLZ}>mb#IHRqZ37oX!`a18+ zdPB0P{JW|%czO1^_@l5}2SZEO*k(NY~xNjymRo?ou zC=z&@HBT#aV%DuXG^HN8d~`XmDV&n_*Z@T$TnMgF6Cwqy^~&S+`a2fRIUbq1Zr&|+ z4HBRasATAheS1+J$ G5AQdfnrKJ> literal 0 HcmV?d00001 diff --git a/reference/gl.loc b/reference/gl.loc new file mode 100644 index 000000000..192d169f2 --- /dev/null +++ b/reference/gl.loc @@ -0,0 +1,56 @@ + + + + +geocache +http://www.geocaching.com/seek/cache_details.asp?ID=3771 + + + + +geocache +http://www.geocaching.com/seek/cache_details.asp?ID=6711 + + + + +geocache +http://www.geocaching.com/seek/cache_details.asp?ID=7211 + + + + +geocache +http://www.geocaching.com/seek/cache_details.asp?ID=9641 + + + + +geocache +http://www.geocaching.com/seek/cache_details.asp?ID=10019 + + + + +geocache +http://www.geocaching.com/seek/cache_details.asp?ID=11121 + + + + +geocache +http://www.geocaching.com/seek/cache_details.asp?ID=12447 + + + + +geocache +http://www.geocaching.com/seek/cache_details.asp?ID=12666 + + + + +geocache +http://www.geocaching.com/seek/cache_details.asp?ID=12669 + + diff --git a/reference/gnuplot.style b/reference/gnuplot.style new file mode 100644 index 000000000..5c5b09e3b --- /dev/null +++ b/reference/gnuplot.style @@ -0,0 +1,26 @@ +# gpsbabel XCSV style file +# +# Format: GnuPlot output for track profiles +# Author: Ron Parker +# Date: 17 Aug 2004 +# +# + +DESCRIPTION Gnuplot track profile + +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER TAB +RECORD_DELIMITER NEWLINE +BADCHARS TAB + +# +# INDIVIDUAL DATA FIELDS: +# +PROLOGUE plot "-" with lines + +IFIELD PATH_DISTANCE_MILES, "", "%.4lf" +IFIELD ALT_FEET, "", "%f" + +EPILOGUE e + diff --git a/reference/gpilots.pdb b/reference/gpilots.pdb new file mode 100644 index 0000000000000000000000000000000000000000..a0bdef97405b6891b233a162020bee5095295883 GIT binary patch literal 2744 zcmYewNzBkINJ(PA1vnTOcU#}m17UO};RPkd?g5!OaB)r`YX*eJxC2NtGB7aR0Mbkh z49q`(G&2JOs|1i{VPIgh0Me`s4D1m=nvH>hqXI~?Gca(@0MZ;_B|ruPgS)eMk~FA@0f$dWMyf(cQGQMiC{Pj&EsP2>bMi|R)D+wjb2D=)i3=LA zs$mj7&PGmiU(b;I?U@b^AD7IsR0XH}+@#bZPzZVDy9WdVLnn>Y&|zR09^qqT>S)P3 zdx7Lh$s}<2xcLW%xCS8y4ao@yn#P7n_?R0R?_gagxlSbz96mnz>4|v?KAGtmB^mjp z#i`JcDkvs7iw%?TaWXfQbXh8S#Ki*~KJJNmnZT^&oR|zOh=3U^nB;O9RzwYt@G&;9 zbh|WprKHJG7jXClXH=>eD|lo=3TU^?qEt6fT1qW)%}X~Xq4pXs<&UwUxudt>5=r0F zrjYcLSyECNT7W2k^cBJri}HX;Dj=~ayBL-@h@gi_`Y|+jiCMEkQqS8896p|TIiU2C NnU_v!5Dn$<0RTDCxT637 literal 0 HcmV?d00001 diff --git a/reference/gpsdrive.txt b/reference/gpsdrive.txt new file mode 100644 index 000000000..901eb1c84 --- /dev/null +++ b/reference/gpsdrive.txt @@ -0,0 +1,9 @@ +GCEBB 35.97203 -87.13470 geocache +GC1A37 36.09068 -86.67955 geocache +GC1C2B 35.99627 -86.62012 geocache +GC25A9 36.03848 -86.64862 geocache +GC2723 36.11218 -86.74177 geocache +GC2B71 36.06408 -86.79052 geocache +GC309F 36.08777 -86.80973 geocache +GC317A 36.05750 -86.89200 geocache +GC317D 36.08280 -86.86728 geocache diff --git a/reference/gpspilot.pdb b/reference/gpspilot.pdb new file mode 100644 index 0000000000000000000000000000000000000000..b4c04f0ae539c339cd038eabca110a10b86a733e GIT binary patch literal 609 zcmaKoze~eF6vyMw)5*>GTogpqBuFa=+O$oov?#VBNI|c9O%CHFBxxa=i(5yL4({%{ zwD@aq6918y#^&c3J8iijb}_j37u-uJz;{m>V#7tQ(y73HsML{ZwE<|978fBT-0 zmY)~h{ZUvo`@cS)K>P3p#ia(X0nlC0LC`bMA7RIWs>WY=l8U`@cMu*&;EFn{JI4uR9>!OjVN$qn=I!R4- zB-|JfHKiwj5zptOy>*OCM$|bqyrT*akXrMsjUo`$E|JzS#aZr<>x&sA%=Ka^yZO`H zEw3%47Qwtf@k;KmPSKqAY$j=5*iPhlwUB>fe)zL1Eurav?L}pBJNB7jF)5&-G~0)f zpsiwWYRyQfVBW1#a#v1bM$w6 + + +ACHNR1Waypoint +ACHNR2Waypoint +ACHNRSWaypoint +HWYB26HWY B265 (NE)HWY B265 (NE)Waypoint +HWYB59Waypoint +L100Waypoint +L1001Waypoint +LXMBR1Waypoint +LXMBR2Waypoint +LXMBRGWaypoint +MLTR10Waypoint +MLTRN1Waypoint +MLTRN2Waypoint +MLTRN3Waypoint +MLTRN4Waypoint +MLTRN5Waypoint +MLTRN6Waypoint +MLTRN7Waypoint +MLTRN8Waypoint +MLTRN9Waypoint +MLTRNGMILITARRINGSTRASSEMILITARRINGSTRASSEWaypoint +ROADWaypoint +UNVRS1Waypoint +UNVRS2Waypoint +UNVRSTWaypoint + +MLTRNG to HWYB26 +MLTRNGMILITARRINGSTRASSEMILITARRINGSTRASSEWaypoint +HWYB59Waypoint +MLTRN1Waypoint +MLTRN2Waypoint +MLTRN3Waypoint +MLTRN4Waypoint +MLTRN5Waypoint +MLTRN6Waypoint +MLTRN7Waypoint +MLTRN8Waypoint + + + diff --git a/reference/holux.wpo b/reference/holux.wpo new file mode 100644 index 0000000000000000000000000000000000000000..13f85ba971208bc8e31da430da2338c1e4c73d6d GIT binary patch literal 25512 zcmeI)yKWOf7{&3k9w*^qAY1~3$|YqSFqjSpqQsKDNNaP6#4FHKL_#Te6`p{K8VC(k zAZRF%5Fi>b1-An8?N&SM8AOAWi2q1dZ0l%r_BWrK6w|ubxw)uCNr`H5s%u8Gn$sTb z)jsW4LkDzFhcvIlI-;XGrUf0>37yo0g#ZG(O~8KXtp7`(duct*T2iyLzHK|bufLs? zB@+8kWS9MH=ZVwDSa#@VUq|*`zrL}ud`_~zO?%UBo=#W4K6AP_H{Bu6wlDbmP98aJ zX*%0)EiL8GP3LQGvTZ;c-aq;4*eU0m8w~+Z;`E-{V}`dcNklT)qumGKgwG6 zbmeDzZoZ!aXOU;q${EMZifpCtFY~<{@GY`u{0<1+x#{H`(912Wy8uD&)V#~jAbile9E#vV%d@Jux%Y~1+sZp76J$$fB*srAb6EBzSQ&o z!?O@T009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** s5I_I{1Q7Vw0-rbTyvpwi|J!SiLwzQ8>nwNCgk<;*0R#|000Cd%H$je|f&c&j literal 0 HcmV?d00001 diff --git a/reference/hsandv.exp b/reference/hsandv.exp new file mode 100644 index 000000000..78c979a7d --- /dev/null +++ b/reference/hsandv.exp @@ -0,0 +1,80 @@ + + + + 1.0000000 + ROUTENAME + 0 + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGCEBBlegnum0usrmrkMountain Bike Heaven by susy1313select2 + attr=grpnamROUTENAME + 1 + 35.972033 + -87.134700 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGC1A37legnum1usrmrkThe Troll by a182pilot & Familyselect2 + attr=grpnamROUTENAME + 1 + 36.090683 + -86.679550 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGC1C2Blegnum2usrmrkDive Bomber by JoGPS & familyselect2 + attr=grpnamROUTENAME + 1 + 35.996267 + -86.620117 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGC25A9legnum3usrmrkFOSTER by JoGPS & Familyselect2 + attr=grpnamROUTENAME + 1 + 36.038483 + -86.648617 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGC2723legnum4usrmrkLogan Lighthouse by JoGps & Familyselect2 + attr=grpnamROUTENAME + 1 + 36.112183 + -86.741767 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGC2B71legnum5usrmrkGanier Cache by Susy1313select2 + attr=grpnamROUTENAME + 1 + 36.064083 + -86.790517 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGC309Flegnum6usrmrkShy's Hill by FireFighterEng33select2 + attr=grpnamROUTENAME + 1 + 36.087767 + -86.809733 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGC317Alegnum7usrmrkGittyUp by JoGPS / Warner Parksselect2 + attr=grpnamROUTENAME + 1 + 36.057500 + -86.892000 + + + waypnt + attr=grpnamROUTENAMEtrnrad50OBJNAMGC317Dlegnum8usrmrkInlighting by JoGPS / Warner Parksselect2 + attr=grpnamROUTENAME + 1 + 36.082800 + -86.867283 + + + diff --git a/reference/human.in b/reference/human.in new file mode 100644 index 000000000..1d6653764 --- /dev/null +++ b/reference/human.in @@ -0,0 +1,7 @@ +W 5 10 15 20 25 30 N +1°23'45.678"S 1°23'45.678"E +12d 34.567m N 76d 54.321m E +N 12.345 W 67.890 +12.345N 67.890W +12.345N W67.890 + diff --git a/reference/humanread.out b/reference/humanread.out new file mode 100644 index 000000000..50093bff1 --- /dev/null +++ b/reference/humanread.out @@ -0,0 +1,6 @@ +20.42500 -5.17083 +-1.39602 01.39602 +12.57612 76.90535 +12.34500 -67.89000 +12.34500 -67.89000 +12.34500 -67.89000 diff --git a/reference/humanread.style b/reference/humanread.style new file mode 100644 index 000000000..28b50c54e --- /dev/null +++ b/reference/humanread.style @@ -0,0 +1,20 @@ +# gpsbabel XCSV style file +# +# Format: Human readable read test style +# Author: Ron Parker +# Date: 21 July 2004 +# + +DESCRIPTION Human readable read test style +EXTENSION txt + +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER TAB +RECORD_DELIMITER NEWLINE + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD LATLON_HUMAN_READABLE, "", "" diff --git a/reference/humanwrite.out b/reference/humanwrite.out new file mode 100644 index 000000000..8d47faba0 --- /dev/null +++ b/reference/humanwrite.out @@ -0,0 +1,6 @@ +N 20.425000 W 5.170833 N 020° 25.500' W 005° 10.250' 20.425000 N 5.170833 W N 20.425000 W 5.170833 N 20 25 30.000000 W 5 10 15.000000 N 20 25 30 W 5 10 15 N 20 W 5 20 degrees 5 degrees +S 1.396022 E 1.396022 S 001° 23.761' E 001° 23.761' 1.396022 S 1.396022 E S 1.396022 E 1.396022 S 1 23 45.678000 E 1 23 45.678000 S 1 23 45 E 1 23 45 S 1 E 1 1 degrees 1 degrees +N 12.576117 E 76.905350 N 012° 34.567' E 076° 54.321' 12.576117 N 76.905350 E N 12.576117 E 76.905350 N 12 34 34.020000 E 76 54 19.260000 N 12 34 34 E 76 54 19 N 12 E 76 12 degrees 76 degrees +N 12.345000 W 67.890000 N 012° 20.700' W 067° 53.400' 12.345000 N 67.890000 W N 12.345000 W 67.890000 N 12 20 42.000000 W 67 53 24.000000 N 12 20 42 W 67 53 24 N 12 W 67 12 degrees 67 degrees +N 12.345000 W 67.890000 N 012° 20.700' W 067° 53.400' 12.345000 N 67.890000 W N 12.345000 W 67.890000 N 12 20 42.000000 W 67 53 24.000000 N 12 20 42 W 67 53 24 N 12 W 67 12 degrees 67 degrees +N 12.345000 W 67.890000 N 012° 20.700' W 067° 53.400' 12.345000 N 67.890000 W N 12.345000 W 67.890000 N 12 20 42.000000 W 67 53 24.000000 N 12 20 42 W 67 53 24 N 12 W 67 12 degrees 67 degrees diff --git a/reference/humanwrite.style b/reference/humanwrite.style new file mode 100644 index 000000000..04bf783ef --- /dev/null +++ b/reference/humanwrite.style @@ -0,0 +1,28 @@ +# gpsbabel XCSV style file +# +# Format: Human readable write test style +# Author: Ron Parker +# Date: 21 July 2004 +# + +DESCRIPTION Human readable write test style +EXTENSION txt + +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER TAB +RECORD_DELIMITER NEWLINE + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD LATLON_HUMAN_READABLE, "", "%c %f" +IFIELD LATLON_HUMAN_READABLE, "", "%c %.3d° %6.3f'" +IFIELD LATLON_HUMAN_READABLE, "", "%f %c" +IFIELD LATLON_HUMAN_READABLE, "", "%c %f" +IFIELD LATLON_HUMAN_READABLE, "", "%c %d %d %f" +IFIELD LATLON_HUMAN_READABLE, "", "%c %d %d %d" +IFIELD LATLON_HUMAN_READABLE, "", "%c %d" +IFIELD LATLON_HUMAN_READABLE, "", "%d degrees" + diff --git a/reference/igc1.gpx b/reference/igc1.gpx new file mode 100644 index 000000000..35191c176 --- /dev/null +++ b/reference/igc1.gpx @@ -0,0 +1,549 @@ + + + + + + PALLMG + PALLMG + PALLMG + dot + + + PILOT + CHRIS JONES + CHRIS JONES + dot + + + PLUMTH + PLUMTHORPE LOC + PLUMTHORPE LOC + dot + + + + +0.000000 + + + +0.000000 + + + + + + #2 +1 + + +0.000000 + + + +0.000000 + + + + + + #3 +2 + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + + + + #4 +3 + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + + + + AB1 + + 0.000000 + BORAH + + + 0.000000 + BALDWI + + + 0.000000 + MANAIR + + + diff --git a/reference/igc1_3d.out b/reference/igc1_3d.out new file mode 100644 index 000000000..21ff7744a --- /dev/null +++ b/reference/igc1_3d.out @@ -0,0 +1,123 @@ +AXXXZZZGPSBabel +HFDTE240404 +HFPLTPILOT:CHRIS JONES +C010170000000000000000101 +C3040552S15036542EBORAH +C3040552S15036542EBORAH +C3043796S15038952EBALDWI +C3045821S15043392EMANAIR +C3045821S15043392EMANAIR +B0400193040579S15036384EA0090000000 +B0400493040614S15036317EA0093400000 +B0401193040699S15036326EA0097000000 +B0401503040629S15036431EA0099400000 +B0402203040628S15036565EA0100000000 +B0402513040689S15036431EA0098000000 +B0403223040555S15036270EA0095500000 +B0403523040720S15036356EA0091800000 +B0404233040884S15036452EA0090300000 +B0404543040658S15036419EA0088900000 +B0405243040811S15036507EA0087100000 +B0405553040688S15036378EA0084200000 +B0406263040714S15036409EA0087100000 +B0406573040686S15036391EA0089700000 +B0407283040728S15036419EA0090300000 +B0407583040656S15036366EA0090000000 +B0408293040785S15036447EA0092000000 +B0409003040822S15036433EA0097100000 +B0409313040795S15036535EA0102000000 +B0410013040809S15036573EA0100900000 +B0410323040819S15036444EA0095500000 +B0411023040785S15036304EA0095200000 +B0411323040816S15036327EA0096400000 +B0412033040846S15036397EA0097500000 +B0412343040813S15036503EA0099100000 +B0413043040760S15036508EA0096800000 +B0413353040694S15036319EA0092600000 +B0414063040538S15036152EA0091100000 +B0414373040695S15036308EA0089200000 +B0415073040758S15036421EA0091300000 +B0415383040766S15036490EA0094000000 +B0416083040753S15036493EA0094900000 +B0416393040739S15036494EA0098200000 +B0417103040750S15036527EA0096900000 +B0417413040819S15036393EA0094100000 +B0418113040806S15036352EA0091300000 +B0418413040569S15036344EA0089900000 +B0419123040526S15036253EA0090600000 +B0419433040646S15036334EA0090300000 +B0420133040794S15036367EA0089500000 +B0420443040707S15036367EA0090300000 +B0421143040678S15036423EA0092200000 +B0421443040658S15036414EA0091400000 +B0422153040772S15036358EA0091900000 +B0422453040722S15036423EA0096100000 +B0423153040717S15036457EA0098800000 +B0423453040700S15036444EA0101900000 +B0424163040689S15036457EA0104100000 +B0424473040753S15036486EA0101900000 +B0425183040750S15036329EA0099200000 +B0425483040794S15036240EA0101900000 +B0426193040688S15036353EA0108000000 +B0426493040679S15036400EA0111700000 +B0427203040754S15036332EA0113300000 +B0427513040693S15036316EA0113200000 +B0428213040918S15036288EA0108900000 +B0428513041173S15036316EA0105800000 +B0429223041467S15036406EA0100600000 +B0429523041752S15036547EA0093900000 +B0430233042022S15036681EA0089600000 +B0430543042288S15036906EA0085800000 +B0431243042359S15037048EA0087200000 +B0431553042430S15037151EA0091200000 +B0432263042348S15037228EA0094700000 +B0432573042410S15037256EA0096600000 +B0433273042612S15037247EA0094700000 +B0433583042857S15037346EA0089500000 +B0434293043064S15037635EA0085800000 +B0435003043168S15037848EA0088900000 +B0435303043193S15037985EA0092100000 +B0436013043182S15037825EA0095200000 +B0436313043184S15037915EA0099500000 +B0437023043122S15038026EA0101100000 +B0437333043136S15037990EA0103500000 +B0438033043131S15038063EA0105600000 +B0438333043209S15037994EA0104000000 +B0439043043449S15038115EA0101700000 +B0439353043669S15038384EA0099400000 +B0440053043786S15038748EA0097100000 +B0440353043743S15038849EA0097300000 +B0441053043773S15038844EA0101200000 +B0441353043804S15038931EA0103500000 +B0442053043778S15039051EA0100700000 +B0442363043815S15038859EA0098400000 +B0443073043844S15038931EA0097600000 +B0443383043886S15038927EA0099500000 +B0444093043845S15038947EA0099400000 +B0444403043904S15038862EA0099000000 +B0445113043934S15038756EA0098000000 +B0445423044092S15038774EA0095300000 +B0446133044150S15039144EA0094600000 +B0446443044370S15039248EA0094100000 +B0447153044594S15039415EA0092800000 +B0447463044804S15039714EA0089700000 +B0448163044963S15040024EA0086900000 +B0448473044982S15040431EA0083300000 +B0449183044991S15040573EA0083000000 +B0449483045154S15040808EA0081500000 +B0450193045342S15041095EA0078100000 +B0450493045484S15041383EA0075000000 +B0451193045595S15041771EA0065700000 +B0451503045744S15042205EA0055400000 +B0452213045844S15042642EA0052000000 +B0452513045936S15042952EA0051100000 +B0453213045839S15043315EA0047600000 +B0453523045915S15043559EA0045500000 +B0454233045918S15043429EA0043300000 +B0454533045933S15043539EA0037900000 +B0455243045817S15043457EA0032800000 +B0455543045823S15043438EA0033000000 +B0456253045831S15043422EA0032900000 +B0456563045845S15043414EA0033000000 +B0457193045848S15043404EA0000000000 +GGPSBabelSecurityRecordGuaranteedToFailVALIChecks diff --git a/reference/igc1_baro.gpx b/reference/igc1_baro.gpx new file mode 100644 index 000000000..2b208ced1 --- /dev/null +++ b/reference/igc1_baro.gpx @@ -0,0 +1,2563 @@ + + + + + PRESALTTRK + Brauniger-IQ Barograph + + +829.000000 + + + +830.000000 + + + +830.000000 + + + +830.000000 + + + +830.000000 + + + +839.000000 + + + +852.000000 + + + +862.000000 + + + +870.000000 + + + +884.000000 + + + +892.000000 + + + +898.000000 + + + +899.000000 + + + +894.000000 + + + +882.000000 + + + +868.000000 + + + +871.000000 + + + +877.000000 + + + +902.000000 + + + +928.000000 + + + +950.000000 + + + +969.000000 + + + +969.000000 + + + +977.000000 + + + +983.000000 + + + +1002.000000 + + + +1016.000000 + + + +1021.000000 + + + +1021.000000 + + + +1015.000000 + + + +1013.000000 + + + +1013.000000 + + + +1013.000000 + + + +1016.000000 + + + +1005.000000 + + + +984.000000 + + + +981.000000 + + + +967.000000 + + + +962.000000 + + + +956.000000 + + + +959.000000 + + + +962.000000 + + + +970.000000 + + + +978.000000 + + + +971.000000 + + + +966.000000 + + + +958.000000 + + + +970.000000 + + + +977.000000 + + + +991.000000 + + + +1003.000000 + + + +1013.000000 + + + +1020.000000 + + + +1010.000000 + + + +1004.000000 + + + +994.000000 + + + +963.000000 + + + +958.000000 + + + +961.000000 + + + +965.000000 + + + +969.000000 + + + +952.000000 + + + +940.000000 + + + +934.000000 + + + +928.000000 + + + +932.000000 + + + +936.000000 + + + +936.000000 + + + +955.000000 + + + +982.000000 + + + +1004.000000 + + + +1017.000000 + + + +1023.000000 + + + +1036.000000 + + + +1043.000000 + + + +1041.000000 + + + +1046.000000 + + + +1037.000000 + + + +1039.000000 + + + +1036.000000 + + + +1017.000000 + + + +1005.000000 + + + +994.000000 + + + +991.000000 + + + +980.000000 + + + +958.000000 + + + +953.000000 + + + +927.000000 + + + +924.000000 + + + +916.000000 + + + +913.000000 + + + +928.000000 + + + +957.000000 + + + +980.000000 + + + +990.000000 + + + +997.000000 + + + +1009.000000 + + + +1039.000000 + + + +1057.000000 + + + +1067.000000 + + + +1056.000000 + + + +1049.000000 + + + +1036.000000 + + + +1031.000000 + + + +1027.000000 + + + +1011.000000 + + + +994.000000 + + + +993.000000 + + + +983.000000 + + + +966.000000 + + + +961.000000 + + + +958.000000 + + + +947.000000 + + + +943.000000 + + + +951.000000 + + + +947.000000 + + + +922.000000 + + + +914.000000 + + + +913.000000 + + + +920.000000 + + + +905.000000 + + + +901.000000 + + + +904.000000 + + + +903.000000 + + + +904.000000 + + + +907.000000 + + + +902.000000 + + + +901.000000 + + + +899.000000 + + + +911.000000 + + + +914.000000 + + + +901.000000 + + + +898.000000 + + + +897.000000 + + + +901.000000 + + + +908.000000 + + + +919.000000 + + + +932.000000 + + + +943.000000 + + + +958.000000 + + + +968.000000 + + + +990.000000 + + + +1009.000000 + + + +1021.000000 + + + +1029.000000 + + + +1027.000000 + + + +1004.000000 + + + +989.000000 + + + +967.000000 + + + +967.000000 + + + +979.000000 + + + +995.000000 + + + +1008.000000 + + + +1030.000000 + + + +1050.000000 + + + +1060.000000 + + + +1042.000000 + + + +1041.000000 + + + +1022.000000 + + + +1008.000000 + + + +1000.000000 + + + +994.000000 + + + +994.000000 + + + +989.000000 + + + +983.000000 + + + +982.000000 + + + +975.000000 + + + +963.000000 + + + +983.000000 + + + +996.000000 + + + +1004.000000 + + + +1005.000000 + + + +990.000000 + + + +1004.000000 + + + +993.000000 + + + +993.000000 + + + +990.000000 + + + +987.000000 + + + +987.000000 + + + +986.000000 + + + +983.000000 + + + +987.000000 + + + +977.000000 + + + +978.000000 + + + +967.000000 + + + +958.000000 + + + +954.000000 + + + +952.000000 + + + +962.000000 + + + +975.000000 + + + +1006.000000 + + + +1036.000000 + + + +1067.000000 + + + +1091.000000 + + + +1097.000000 + + + +1090.000000 + + + +1035.000000 + + + +1037.000000 + + + +1010.000000 + + + +990.000000 + + + +983.000000 + + + +972.000000 + + + +966.000000 + + + +970.000000 + + + +985.000000 + + + +995.000000 + + + +1024.000000 + + + +1051.000000 + + + +1061.000000 + + + +1098.000000 + + + +1124.000000 + + + +1140.000000 + + + +1127.000000 + + + +1128.000000 + + + +1142.000000 + + + +1150.000000 + + + +1148.000000 + + + +1131.000000 + + + +1148.000000 + + + +1165.000000 + + + +1155.000000 + + + +1162.000000 + + + +1146.000000 + + + +1137.000000 + + + +1128.000000 + + + +1120.000000 + + + +1099.000000 + + + +1076.000000 + + + +1059.000000 + + + +1061.000000 + + + +1054.000000 + + + +1058.000000 + + + +1069.000000 + + + +1074.000000 + + + +1072.000000 + + + +1089.000000 + + + +1107.000000 + + + +1122.000000 + + + +1144.000000 + + + +1156.000000 + + + +1154.000000 + + + +1155.000000 + + + +1163.000000 + + + +1169.000000 + + + +1179.000000 + + + +1188.000000 + + + +1181.000000 + + + +1171.000000 + + + +1153.000000 + + + +1142.000000 + + + +1123.000000 + + + +1103.000000 + + + +1087.000000 + + + +1067.000000 + + + +1051.000000 + + + +1041.000000 + + + +1019.000000 + + + +1015.000000 + + + +995.000000 + + + +983.000000 + + + +963.000000 + + + +951.000000 + + + +939.000000 + + + +940.000000 + + + +944.000000 + + + +944.000000 + + + +937.000000 + + + +939.000000 + + + +940.000000 + + + +945.000000 + + + +943.000000 + + + +933.000000 + + + +926.000000 + + + +924.000000 + + + +912.000000 + + + +906.000000 + + + +907.000000 + + + +901.000000 + + + +893.000000 + + + +892.000000 + + + +888.000000 + + + +882.000000 + + + +889.000000 + + + +900.000000 + + + +896.000000 + + + +881.000000 + + + +878.000000 + + + +887.000000 + + + +890.000000 + + + +888.000000 + + + +892.000000 + + + +891.000000 + + + +892.000000 + + + +888.000000 + + + +893.000000 + + + +881.000000 + + + +889.000000 + + + +883.000000 + + + +889.000000 + + + +890.000000 + + + +895.000000 + + + +900.000000 + + + +901.000000 + + + +905.000000 + + + +904.000000 + + + +893.000000 + + + +888.000000 + + + +879.000000 + + + +868.000000 + + + +857.000000 + + + +855.000000 + + + +858.000000 + + + +858.000000 + + + +858.000000 + + + +852.000000 + + + +852.000000 + + + +865.000000 + + + +861.000000 + + + +848.000000 + + + +854.000000 + + + +860.000000 + + + +862.000000 + + + +859.000000 + + + +873.000000 + + + +904.000000 + + + +929.000000 + + + +941.000000 + + + +931.000000 + + + +938.000000 + + + +938.000000 + + + +934.000000 + + + +943.000000 + + + +941.000000 + + + +942.000000 + + + +922.000000 + + + +904.000000 + + + +896.000000 + + + +878.000000 + + + +869.000000 + + + +873.000000 + + + +872.000000 + + + +874.000000 + + + +864.000000 + + + +874.000000 + + + +896.000000 + + + +898.000000 + + + +891.000000 + + + +899.000000 + + + +881.000000 + + + +885.000000 + + + +917.000000 + + + +919.000000 + + + +917.000000 + + + +926.000000 + + + +926.000000 + + + +945.000000 + + + +962.000000 + + + +971.000000 + + + +981.000000 + + + +985.000000 + + + +987.000000 + + + +1003.000000 + + + +981.000000 + + + +960.000000 + + + +939.000000 + + + +929.000000 + + + +949.000000 + + + +947.000000 + + + +945.000000 + + + +939.000000 + + + +931.000000 + + + +915.000000 + + + +909.000000 + + + +909.000000 + + + +895.000000 + + + +882.000000 + + + +882.000000 + + + +900.000000 + + + +920.000000 + + + +933.000000 + + + +963.000000 + + + +969.000000 + + + +964.000000 + + + +944.000000 + + + +942.000000 + + + +928.000000 + + + +924.000000 + + + +916.000000 + + + +908.000000 + + + +889.000000 + + + +893.000000 + + + +891.000000 + + + +898.000000 + + + +896.000000 + + + +895.000000 + + + +885.000000 + + + +883.000000 + + + +890.000000 + + + +903.000000 + + + +904.000000 + + + +906.000000 + + + +915.000000 + + + +922.000000 + + + +919.000000 + + + +931.000000 + + + +920.000000 + + + +905.000000 + + + +889.000000 + + + +892.000000 + + + +904.000000 + + + +918.000000 + + + +943.000000 + + + +953.000000 + + + +979.000000 + + + +985.000000 + + + +998.000000 + + + +1005.000000 + + + +999.000000 + + + +980.000000 + + + +981.000000 + + + +964.000000 + + + +954.000000 + + + +931.000000 + + + +916.000000 + + + +907.000000 + + + +903.000000 + + + +893.000000 + + + +889.000000 + + + +876.000000 + + + +871.000000 + + + +848.000000 + + + +841.000000 + + + +858.000000 + + + +869.000000 + + + +886.000000 + + + +896.000000 + + + +901.000000 + + + +905.000000 + + + +901.000000 + + + +902.000000 + + + +898.000000 + + + +913.000000 + + + +935.000000 + + + +959.000000 + + + +990.000000 + + + +1013.000000 + + + +1030.000000 + + + +1027.000000 + + + +990.000000 + + + +958.000000 + + + +953.000000 + + + +957.000000 + + + +949.000000 + + + +960.000000 + + + +968.000000 + + + +971.000000 + + + +979.000000 + + + +991.000000 + + + +991.000000 + + + +989.000000 + + + +958.000000 + + + +935.000000 + + + +924.000000 + + + +919.000000 + + + +909.000000 + + + +891.000000 + + + +893.000000 + + + +907.000000 + + + +915.000000 + + + +925.000000 + + + +942.000000 + + + +955.000000 + + + +949.000000 + + + +971.000000 + + + +982.000000 + + + +985.000000 + + + +971.000000 + + + +955.000000 + + + +942.000000 + + + +936.000000 + + + +915.000000 + + + +905.000000 + + + +898.000000 + + + +908.000000 + + + +906.000000 + + + +906.000000 + + + +905.000000 + + + +900.000000 + + + +897.000000 + + + +892.000000 + + + +899.000000 + + + +911.000000 + + + +919.000000 + + + +930.000000 + + + +917.000000 + + + +910.000000 + + + +912.000000 + + + +930.000000 + + + +954.000000 + + + +973.000000 + + + +987.000000 + + + +991.000000 + + + +1013.000000 + + + +1029.000000 + + + +1038.000000 + + + +1046.000000 + + + +1032.000000 + + + +1008.000000 + + + +997.000000 + + + +989.000000 + + + +1006.000000 + + + +1028.000000 + + + +1068.000000 + + + +1086.000000 + + + +1109.000000 + + + +1122.000000 + + + +1131.000000 + + + +1134.000000 + + + +1143.000000 + + + +1130.000000 + + + +1112.000000 + + + +1084.000000 + + + +1068.000000 + + + +1056.000000 + + + +1032.000000 + + + +1002.000000 + + + +966.000000 + + + +935.000000 + + + +918.000000 + + + +895.000000 + + + +872.000000 + + + +858.000000 + + + +866.000000 + + + +872.000000 + + + +890.000000 + + + +911.000000 + + + +926.000000 + + + +946.000000 + + + +960.000000 + + + +968.000000 + + + +959.000000 + + + +952.000000 + + + +930.000000 + + + +901.000000 + + + +880.000000 + + + +861.000000 + + + +852.000000 + + + +880.000000 + + + +904.000000 + + + +920.000000 + + + +923.000000 + + + +941.000000 + + + +965.000000 + + + +987.000000 + + + +1006.000000 + + + +1012.000000 + + + +1011.000000 + + + +1031.000000 + + + +1039.000000 + + + +1054.000000 + + + +1058.000000 + + + +1046.000000 + + + +1037.000000 + + + +1023.000000 + + + +1015.000000 + + + +1003.000000 + + + +991.000000 + + + +978.000000 + + + +969.000000 + + + +972.000000 + + + +974.000000 + + + +989.000000 + + + +1021.000000 + + + +1022.000000 + + + +1040.000000 + + + +1027.000000 + + + +1000.000000 + + + +976.000000 + + + +986.000000 + + + +982.000000 + + + +976.000000 + + + +983.000000 + + + +996.000000 + + + +994.000000 + + + +994.000000 + + + +986.000000 + + + +991.000000 + + + +990.000000 + + + +983.000000 + + + +965.000000 + + + +953.000000 + + + +953.000000 + + + +945.000000 + + + +949.000000 + + + +943.000000 + + + +939.000000 + + + +931.000000 + + + +925.000000 + + + +899.000000 + + + +895.000000 + + + +876.000000 + + + +862.000000 + + + +840.000000 + + + +828.000000 + + + +829.000000 + + + +831.000000 + + + +830.000000 + + + +806.000000 + + + +796.000000 + + + +774.000000 + + + +767.000000 + + + +742.000000 + + + +705.000000 + + + +633.000000 + + + +577.000000 + + + +546.000000 + + + +516.000000 + + + +522.000000 + + + +512.000000 + + + +511.000000 + + + +499.000000 + + + +471.000000 + + + +457.000000 + + + +455.000000 + + + +455.000000 + + + +432.000000 + + + +400.000000 + + + +378.000000 + + + +342.000000 + + + +328.000000 + + + +329.000000 + + + +330.000000 + + + +330.000000 + + + +329.000000 + + + +330.000000 + + + +330.000000 + + + +330.000000 + + + + + diff --git a/reference/igc1_gpx.out b/reference/igc1_gpx.out new file mode 100644 index 000000000..9dc64d888 --- /dev/null +++ b/reference/igc1_gpx.out @@ -0,0 +1,378 @@ + + + + + GNSSALTTRK + IGCHDRS~HFPLTPILOT:CHRIS JONES~ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0001 + IGCDATE000000: + + TAKEOFF + BORAH + + + START + BORAH + + + TURN01 + BALDWI + + + FINISH + MANAIR + + + LANDING + MANAIR + + + diff --git a/reference/igc1_igc.out b/reference/igc1_igc.out new file mode 100644 index 000000000..beb86d8e2 --- /dev/null +++ b/reference/igc1_igc.out @@ -0,0 +1,123 @@ +AXXXZZZGPSBabel +HFDTE240404 +HFPLTPILOT:CHRIS JONES +C010170000000000000000101 +C3040552S15036542EBORAH +C3040552S15036542EBORAH +C3043796S15038952EBALDWI +C3045821S15043392EMANAIR +C3045821S15043392EMANAIR +B0400193040579S15036384EA0000000000 +B0400493040614S15036317EA0000000000 +B0401193040699S15036326EA0000000000 +B0401503040629S15036431EA0000000000 +B0402203040628S15036565EA0000000000 +B0402513040689S15036431EA0000000000 +B0403223040555S15036270EA0000000000 +B0403523040720S15036356EA0000000000 +B0404233040884S15036452EA0000000000 +B0404543040658S15036419EA0000000000 +B0405243040811S15036507EA0000000000 +B0405553040688S15036378EA0000000000 +B0406263040714S15036409EA0000000000 +B0406573040686S15036391EA0000000000 +B0407283040728S15036419EA0000000000 +B0407583040656S15036366EA0000000000 +B0408293040785S15036447EA0000000000 +B0409003040822S15036433EA0000000000 +B0409313040795S15036535EA0000000000 +B0410013040809S15036573EA0000000000 +B0410323040819S15036444EA0000000000 +B0411023040785S15036304EA0000000000 +B0411323040816S15036327EA0000000000 +B0412033040846S15036397EA0000000000 +B0412343040813S15036503EA0000000000 +B0413043040760S15036508EA0000000000 +B0413353040694S15036319EA0000000000 +B0414063040538S15036152EA0000000000 +B0414373040695S15036308EA0000000000 +B0415073040758S15036421EA0000000000 +B0415383040766S15036490EA0000000000 +B0416083040753S15036493EA0000000000 +B0416393040739S15036494EA0000000000 +B0417103040750S15036527EA0000000000 +B0417413040819S15036393EA0000000000 +B0418113040806S15036352EA0000000000 +B0418413040569S15036344EA0000000000 +B0419123040526S15036253EA0000000000 +B0419433040646S15036334EA0000000000 +B0420133040794S15036367EA0000000000 +B0420443040707S15036367EA0000000000 +B0421143040678S15036423EA0000000000 +B0421443040658S15036414EA0000000000 +B0422153040772S15036358EA0000000000 +B0422453040722S15036423EA0000000000 +B0423153040717S15036457EA0000000000 +B0423453040700S15036444EA0000000000 +B0424163040689S15036457EA0000000000 +B0424473040753S15036486EA0000000000 +B0425183040750S15036329EA0000000000 +B0425483040794S15036240EA0000000000 +B0426193040688S15036353EA0000000000 +B0426493040679S15036400EA0000000000 +B0427203040754S15036332EA0000000000 +B0427513040693S15036316EA0000000000 +B0428213040918S15036288EA0000000000 +B0428513041173S15036316EA0000000000 +B0429223041467S15036406EA0000000000 +B0429523041752S15036547EA0000000000 +B0430233042022S15036681EA0000000000 +B0430543042288S15036906EA0000000000 +B0431243042359S15037048EA0000000000 +B0431553042430S15037151EA0000000000 +B0432263042348S15037228EA0000000000 +B0432573042410S15037256EA0000000000 +B0433273042612S15037247EA0000000000 +B0433583042857S15037346EA0000000000 +B0434293043064S15037635EA0000000000 +B0435003043168S15037848EA0000000000 +B0435303043193S15037985EA0000000000 +B0436013043182S15037825EA0000000000 +B0436313043184S15037915EA0000000000 +B0437023043122S15038026EA0000000000 +B0437333043136S15037990EA0000000000 +B0438033043131S15038063EA0000000000 +B0438333043209S15037994EA0000000000 +B0439043043449S15038115EA0000000000 +B0439353043669S15038384EA0000000000 +B0440053043786S15038748EA0000000000 +B0440353043743S15038849EA0000000000 +B0441053043773S15038844EA0000000000 +B0441353043804S15038931EA0000000000 +B0442053043778S15039051EA0000000000 +B0442363043815S15038859EA0000000000 +B0443073043844S15038931EA0000000000 +B0443383043886S15038927EA0000000000 +B0444093043845S15038947EA0000000000 +B0444403043904S15038862EA0000000000 +B0445113043934S15038756EA0000000000 +B0445423044092S15038774EA0000000000 +B0446133044150S15039144EA0000000000 +B0446443044370S15039248EA0000000000 +B0447153044594S15039415EA0000000000 +B0447463044804S15039714EA0000000000 +B0448163044963S15040024EA0000000000 +B0448473044982S15040431EA0000000000 +B0449183044991S15040573EA0000000000 +B0449483045154S15040808EA0000000000 +B0450193045342S15041095EA0000000000 +B0450493045484S15041383EA0000000000 +B0451193045595S15041771EA0000000000 +B0451503045744S15042205EA0000000000 +B0452213045844S15042642EA0000000000 +B0452513045936S15042952EA0000000000 +B0453213045839S15043315EA0000000000 +B0453523045915S15043559EA0000000000 +B0454233045918S15043429EA0000000000 +B0454533045933S15043539EA0000000000 +B0455243045817S15043457EA0000000000 +B0455543045823S15043438EA0000000000 +B0456253045831S15043422EA0000000000 +B0456563045845S15043414EA0000000000 +B0457193045848S15043404EA0000000000 +GGPSBabelSecurityRecordGuaranteedToFailVALIChecks diff --git a/reference/igc2.igc b/reference/igc2.igc new file mode 100644 index 000000000..b07594187 --- /dev/null +++ b/reference/igc2.igc @@ -0,0 +1,46 @@ +AXXXABCFLIGHT:1 +HFFXA035 +HFDTE160701 +HFPLTPILOT:Bill Bloggs +HFGTYGLIDERTYPE:Schleicher ASH-25 +HFGIDGLIDERID:ABCD-1234 +HFDTM100GPSDATUM:WGS-1984 +HFRFWFIRMWAREVERSION:6.4 +HFRHWHARDWAREVERSION:3.0 +HFFTYFRTYPE:Manufacturer Model +HFGPSMarconiCanada:Superstar 12ch max10000m +HFPRSPRESSALTSENSOR:Sensyn XYZ1111 max11000m +HFCIDCOMPETITIONID:XYZ-78910 +HFCCLCOMPETITIONCLASS:15mMotor Glider +HFSCMSECONDCREW:JohnSmith +I023638FXA3941ENL +J010812HDT +C150701213841160701000102500KTri +C5111359N00101899WLashamClubhouse +C5110179N00102644WLashamStart S Start +C5209092N00255227WSarnesfield TP1 +C5230147N00017612WNormanCross TP2 +C5110179N00102644WLashamStart S Finish +C5111359N00101899WLashamClubhouse +F160240040609123624221821 +B1602405407121N00249342WA0028000421020509950 +D20331 +E160245PEV +B1602455107126N00149300WA0028800429019509020 +B1602505107134N00149283WA0029000432021009015 +B1602555107140N00149221WA0029000430020009012 +F1603000609123624221821 +B1603005107150N00149202WA0029100432025608009 +E160305PEV +B1603055107180N00149185WA0029100435021008015 +B1603105107212N00149174WA0029300435019608024 +K160248090 +B1602485107220N00149150WA0049400436019008018 +B1602525107330N00149127WA0049600439019508015 +LXXXRURITANIANSTANDARD NATIONALS DAY 1 +LXXXFLIGHTTIME: 4:14:25 TASK SPEED:58.48KTS +GREJNGJERJKNJKRE31895478537H43982FJN9248F942389T433T +GJNJK1489IERGNV3089IVJE9GO398535J3894N358954983O0934 +GSKTO5427FGTNUT5621WKTC6714FT8957FGMKJ134527FGTR6751 +GK2489IERGNV3089IVJE39GO398535J3894N358954983FTGY546 +G12560DJUWT28719GTAOL5628FGWNIST78154INWTOLP7815FITN diff --git a/reference/igc2_gpx.out b/reference/igc2_gpx.out new file mode 100644 index 000000000..6b2e34087 --- /dev/null +++ b/reference/igc2_gpx.out @@ -0,0 +1,127 @@ + + + + + PRESALTTRK + IGCHDRS~HFFXA035~HFPLTPILOT:Bill Bloggs~HFGTYGLIDERTYPE:Schleicher ASH-25~HFGIDGLIDERID:ABCD-1234~HFDTM100GPSDATUM:WGS-1984~HFRFWFIRMWAREVERSION:6.4~HFRHWHARDWAREVERSION:3.0~HFFTYFRTYPE:Manufacturer Model~HFGPSMarconiCanada:Superstar 12ch max10000m~HFPRSPRESSALTSENSOR:Sensyn XYZ1111 max11000m~HFCIDCOMPETITIONID:XYZ-78910~HFCCLCOMPETITIONCLASS:15mMotor Glider~HFSCMSECONDCREW:JohnSmith~ + + +280.000000 + + + +288.000000 + + + +290.000000 + + + +290.000000 + + + +291.000000 + + + +291.000000 + + + +293.000000 + + + +494.000000 + + + +496.000000 + + + + + + GNSSALTTRK + IGCHDRS~HFFXA035~HFPLTPILOT:Bill Bloggs~HFGTYGLIDERTYPE:Schleicher ASH-25~HFGIDGLIDERID:ABCD-1234~HFDTM100GPSDATUM:WGS-1984~HFRFWFIRMWAREVERSION:6.4~HFRHWHARDWAREVERSION:3.0~HFFTYFRTYPE:Manufacturer Model~HFGPSMarconiCanada:Superstar 12ch max10000m~HFPRSPRESSALTSENSOR:Sensyn XYZ1111 max11000m~HFCIDCOMPETITIONID:XYZ-78910~HFCCLCOMPETITIONCLASS:15mMotor Glider~HFSCMSECONDCREW:JohnSmith~ + + +421.000000 + + + +429.000000 + + + +432.000000 + + + +430.000000 + + + +432.000000 + + + +435.000000 + + + +435.000000 + + + +436.000000 + + + +439.000000 + + + + + + 0001 + IGCDATE160701: 500KTri + + + TAKEOFF + LashamClubhouse + + + + START + LashamStart S Start + + + + TURN01 + Sarnesfield TP1 + + + + TURN02 + NormanCross TP2 + + + + FINISH + LashamStart S Finish + + + + LANDING + LashamClubhouse + + + diff --git a/reference/igc2_igc.out b/reference/igc2_igc.out new file mode 100644 index 000000000..877a5bcba --- /dev/null +++ b/reference/igc2_igc.out @@ -0,0 +1,32 @@ +AXXXZZZGPSBabel +HFDTE160701 +HFFXA035 +HFPLTPILOT:Bill Bloggs +HFGTYGLIDERTYPE:Schleicher ASH-25 +HFGIDGLIDERID:ABCD-1234 +HFDTM100GPSDATUM:WGS-1984 +HFRFWFIRMWAREVERSION:6.4 +HFRHWHARDWAREVERSION:3.0 +HFFTYFRTYPE:Manufacturer Model +HFGPSMarconiCanada:Superstar 12ch max10000m +HFPRSPRESSALTSENSOR:Sensyn XYZ1111 max11000m +HFCIDCOMPETITIONID:XYZ-78910 +HFCCLCOMPETITIONCLASS:15mMotor Glider +HFSCMSECONDCREW:JohnSmith +C150701213841160701000102500KTri +C5111359N00101899WLashamClubhouse +C5110179N00102644WLashamStart S Start +C5209092N00255227WSarnesfield TP1 +C5230147N00017612WNormanCross TP2 +C5110179N00102644WLashamStart S Finish +C5111359N00101899WLashamClubhouse +B1602405407121N00249342WA0028000421 +B1602455107126N00149300WA0028800429 +B1602505107134N00149283WA0029000432 +B1602555107140N00149221WA0029000430 +B1603005107150N00149202WA0029100432 +B1603055107180N00149185WA0029100435 +B1603105107212N00149174WA0029300435 +B1602485107220N00149150WA0049400436 +B1602525107330N00149127WA0049600439 +GGPSBabelSecurityRecordGuaranteedToFailVALIChecks diff --git a/reference/magfile b/reference/magfile new file mode 100644 index 000000000..26216d129 --- /dev/null +++ b/reference/magfile @@ -0,0 +1,18 @@ +$PMGNWPL,2805.200,N,08246.200,W,0000000,M,AL7394,872 6833 A TIDAL,a*43 +$PMGNWPL,2806.216,N,08246.733,W,0000000,M,AL7485,872 6853 TIDAL 1,a*33 +$PMGNWPL,2806.216,N,08246.733,W,0000000,M,AL7484,872 6853 TIDAL 2,a*31 +$PMGNWPL,2806.050,N,08246.367,W,0000000,M,AL7482,872 6853 TIDAL 4,a*34 +$PMGNWPL,2808.816,N,08245.483,W,0000000,M,AL7471,872 6892 TIDAL 1,a*3A +$PMGNWPL,2808.816,N,08245.483,W,0000000,M,AL7470,872 6892 TIDAL 2,a*38 +$PMGNWPL,2809.017,N,08246.283,W,0000000,M,AL7380,872 6899 TIDAL 1,a*35 +$PMGNWPL,2809.017,N,08246.283,W,0000000,M,AL7379,872 6899 TIDAL 2,a*30 +$PMGNWPL,2809.017,N,08246.283,W,0000000,M,AL7378,872 6899 TIDAL 3,a*30 +$PMGNWPL,2809.017,N,08246.283,W,0000000,M,AL7377,872 6899 TIDAL 4,a*38 +$PMGNWPL,2809.017,N,08246.283,W,0000000,M,AL7376,872 6899 TIDAL 5,a*38 +$PMGNWPL,2809.216,N,08248.033,W,0000000,M,AL7386,872 6904 TIDAL 1,a*32 +$PMGNWPL,2809.216,N,08248.033,W,0000000,M,AL7385,872 6904 TIDAL 2,a*32 +$PMGNWPL,2809.216,N,08248.033,W,0000000,M,AL7384,872 6904 TIDAL 3,a*32 +$PMGNWPL,2809.216,N,08248.017,W,0000000,M,AL7383,872 6904 TIDAL 4,a*34 +$PMGNWPL,2809.216,N,08248.017,W,0000000,M,AL7382,872 6904 TIDAL 5,a*34 +$PMGNWPL,2809.617,N,08245.933,W,0000000,M,AL6625,872 6905 TIDAL 5,a*3B +$PMGNWPL,2809.383,N,08244.666,W,0000000,M,AL7392,872 6906 TIDAL 2,a*31 diff --git a/reference/magnav.pdb b/reference/magnav.pdb new file mode 100644 index 0000000000000000000000000000000000000000..77be3af4cfe500cc2b1694c02c126527cb1e5071 GIT binary patch literal 1160 zcmd^i>6OF6C5v-$QO*u5d9T- zq-~A<_>_!}{cp*<_R*IMuG~!b`w`Oi?^c=u)ey>5Kr`@s2kim90?oqI2JHpi1?>Yp z1I@vw3D7(YZ7HMy=>Hp9rYGCmm&^CRD7+jP97+qJAuZ?qvzk2rs^S7v8iKfX*|N}r zXmLpx#}-?oc$SiN%JE8s!&VsShHj(`Xw+j!bNE8V2ghxsUNTHnYfxMZgy$t7qE8il z<_U?%utS>6i=IPHUKUjR6Z#JUE_J(Tp&7PLu_c--G)SQDgu7S;;A(fkKc7{6_^S;p zzAa57=Y6$Su5_}xGiQ!eRJ^yHvdp4^=0%-wJkRP4*$}Oe-c$YXKIPlPx34E^m;--b zWXiNm9l7wsL9RCW0L6ritKIhF)sc#KuG=hQeA+?PM)W$wv+S-R4hyK0c%?y^*Nx{p zoc*n0c9IfxvxHnGWwhi!l-Rgwl3F^6C(7(y~q6+(*gb8-}tDisn9EsP2>bMi|R)D+wj zb2D=);p*TFAvg<_Q3d3J9N=u^gpfe8|3Ab53t!KW{O*~KaDYo@S*n6ler{4~5y%N% z`R)P1K;w7wK#y^*P-B|hspXD^UEDw%|^-pxNa#5D-nW>P&~54G9c$QYl^TUggg zu2Km^*zA*^o|vcLlbN1Tl969poC ztl*IeNqBCVMX7F}kVq|Z%}X~X!G37EH#RhP#Am;^;1WsS)20af-7`x{Dnknp5wEWh zo>-Iz42*!pqU>UXSuhr^0Dwk6&;c$mrPu->X3YvoBX28&13dF`KpxJ_OQ+lo&_Hl? ya>C~XyQV3UE9Y<`oZy>ZnpcvTnWx~CnVqWOk(yYRng?=BG0CZb321K^10w)x$S3sx literal 0 HcmV?d00001 diff --git a/reference/mps-empty.mps b/reference/mps-empty.mps new file mode 100644 index 0000000000000000000000000000000000000000..154785e977422e6b591ec800a516e49ac5a376dc GIT binary patch literal 52 zcmeY*4oXg8U}9ika7kg122zfCjKP794F1U_3PuJBhL)C=42DKlrUq8V#$aV(42%H! C@CcIt literal 0 HcmV?d00001 diff --git a/reference/mxf.mxf b/reference/mxf.mxf new file mode 100644 index 000000000..98d93d1a0 --- /dev/null +++ b/reference/mxf.mxf @@ -0,0 +1,9 @@ +35.97203, -87.13470, "Mountain Bike Heaven by susy1313", "GCEBB", "Mountain Bike Heaven by susy1313", ff0000, 47 +36.09068, -86.67955, "The Troll by a182pilot & Family", "GC1A37", "The Troll by a182pilot & Family", ff0000, 47 +35.99627, -86.62012, "Dive Bomber by JoGPS & family", "GC1C2B", "Dive Bomber by JoGPS & family", ff0000, 47 +36.03848, -86.64862, "FOSTER by JoGPS & Family", "GC25A9", "FOSTER by JoGPS & Family", ff0000, 47 +36.11218, -86.74177, "Logan Lighthouse by JoGps & Family", "GC2723", "Logan Lighthouse by JoGps & Family", ff0000, 47 +36.06408, -86.79052, "Ganier Cache by Susy1313", "GC2B71", "Ganier Cache by Susy1313", ff0000, 47 +36.08777, -86.80973, "Shy's Hill by FireFighterEng33", "GC309F", "Shy's Hill by FireFighterEng33", ff0000, 47 +36.05750, -86.89200, "GittyUp by JoGPS / Warner Parks", "GC317A", "GittyUp by JoGPS / Warner Parks", ff0000, 47 +36.08280, -86.86728, "Inlighting by JoGPS / Warner Parks", "GC317D", "Inlighting by JoGPS / Warner Parks", ff0000, 47 diff --git a/reference/navicache.ref b/reference/navicache.ref new file mode 100644 index 000000000..b74e217a4 --- /dev/null +++ b/reference/navicache.ref @@ -0,0 +1,2 @@ +2343 3334.415N 11146.587W 0000000m Eagle's Nest a +2342 3431.053N 11146.178W 0000000m Clear Creek Cache a diff --git a/reference/navicache.xml b/reference/navicache.xml new file mode 100644 index 000000000..becb69879 --- /dev/null +++ b/reference/navicache.xml @@ -0,0 +1,91 @@ + + + + + + + + + diff --git a/reference/netstumbler.mps b/reference/netstumbler.mps new file mode 100644 index 0000000000000000000000000000000000000000..c313182348d1eae58d4d4ff2e7046dd3296e030e GIT binary patch literal 4838 zcmb7IONbm*6s=JaC5wm%;s@=A5CVoCddeM&qAUc;BmB?Y-pt7t=9Hy=yHe3B8l}2I>!6#U>&ol=|IK!=em2|+ z`Q_+y8+{Zd`Lg(4OyKKd-=t3{s#;lgx?y#`Rk5nn2Wo+4LaheW1J(ckF=b|Sd05^W zyE@OmH9h9r{q~0Z2a11t2!LIP$=lx}0CZn`6HE_$8+;vfL#{L_{+mhslN-!#Z?vka zd@qaO@f^$;6c3(buL1liYas`3Ly;If!kRx1MuLF5xMmg0&kpPu}&Erp@0Z|2~EsLV!&4!=XA~ zpL9DLrR>js8$1p2U-F_bD*w*n}eb#6R#y)YzBT%#=&FfV{+&>6g{^V4Lz}> zh9_5=ln7ymUfAt+Hd#-;mQBL%PY%d@fBRpc0inuMN(aOLL#30DyWq=aE1q^8Kr zv4(bYAPB8aKV+{?7|ynT84x&;4?z>Y?DLrnsKW~p=oGamTGMDcs3P{VEIh=u@XP{& zfV40+ANXL`_?#jcJrE7)IRSZU7DGbAI?cy`3WB>ry#^|(tw|6>L97OD%kCi+X92wX z!+`v81OY%&u&M^HLJevjZ~zVkV+vEa!0Bo>gC1+MFf8}wcdib|%d-eWK_c`9*nC(< zNu9)knABG~J?{+atJ9K@9NERB&TMe_X)PxUMXn$k!$xOKN+%n9cP}Q}?;}r?ePN_R zVM!KEYaoSNYEs7N5|; zpmM1+_eI>Nr$p9n%a^iyzx)1}&>ciSijOKV`LTcx={fO>>{#^Wv;fKw+#AN^`ak&y agd6j7GC!p9Q+kb`RHi_X{IK<+GV>p=4wgOu literal 0 HcmV?d00001 diff --git a/reference/netstumbler.txt b/reference/netstumbler.txt new file mode 100644 index 000000000..712999c3b --- /dev/null +++ b/reference/netstumbler.txt @@ -0,0 +1,42 @@ +# $Creator: Network Stumbler Version 0.4.0 +# $Format: wi-scan summary with extensions +# Latitude Longitude ( SSID ) Type ( BSSID ) Time (GMT) [ SNR Sig Noise ] # ( Name ) Flags Channelbits BcnIntvl DataRate LastChannel +# $DateGMT: 2004-06-05 +N 47.7111183 W 91.0121750 ( linksys ) BSS ( 0f:06:25:77:0d:1f ) 01:22:09 (GMT) [ 24 73 49 ] # ( ) 0001 00000040 100 110 6 +N 47.7108850 W 91.0120617 ( default ) BSS ( 0f:05:5d:fa:f3:34 ) 01:22:18 (GMT) [ 26 75 49 ] # ( ) 0401 00000040 100 0 6 +N 47.7096033 W 91.0143300 ( ) BSS ( 0f:40:96:44:c0:cc ) 01:24:16 (GMT) [ 16 65 49 ] # ( ) 0011 00000040 100 110 6 +N 47.7088850 W 91.0146683 ( msu88 ) BSS ( 0f:0c:41:bc:2a:8c ) 01:24:31 (GMT) [ 36 85 49 ] # ( ) 0005 00000040 100 110 6 +N 47.7077150 W 91.0151333 ( linksys ) BSS ( 0f:06:25:a4:77:2e ) 01:24:53 (GMT) [ 25 74 49 ] # ( ) 0001 00000040 100 110 6 +N 47.7072867 W 91.0152633 ( default ) BSS ( 0f:0d:88:8d:16:4f ) 01:25:04 (GMT) [ 32 81 49 ] # ( ) 0421 00000040 100 540 6 +N 47.7069517 W 91.0153133 ( silicon ) BSS ( 0f:30:bd:c1:3b:16 ) 01:25:10 (GMT) [ 29 78 49 ] # ( ) 0011 00000040 100 110 6 +N 47.7066100 W 91.0153683 ( purnet ) BSS ( 0f:0c:41:ab:45:66 ) 01:25:19 (GMT) [ 20 69 49 ] # ( ) 0401 00000040 100 540 6 +N 47.7066783 W 91.0157867 ( Harvey ) BSS ( 0f:0d:88:1e:a5:6e ) 01:25:30 (GMT) [ 13 62 49 ] # ( ) 0001 00000100 100 110 8 +N 47.7066550 W 91.0136367 ( X6604 ) BSS ( 0f:a0:c5:69:65:10 ) 01:26:19 (GMT) [ 17 66 49 ] # ( ) 0001 00000040 100 110 6 +N 47.7067600 W 91.0133900 ( Scott ) BSS ( 0f:0d:93:88:3f:c1 ) 01:26:39 (GMT) [ 17 66 49 ] # ( ) 0411 00000400 100 540 10 +N 47.7070583 W 91.0128933 ( NETGEAR ) BSS ( 0f:09:5b:6e:59:90 ) 01:26:44 (GMT) [ 25 74 49 ] # ( ) 0005 00000800 100 110 11 +N 47.7069967 W 91.0129867 ( ) BSS ( 00:05:5d:fb:02:bf ) 01:26:49 (GMT) [ 15 64 49 ] # ( ) 0411 00000020 100 540 5 +N 47.7062300 W 91.0118067 ( cones ) BSS ( 0f:40:96:25:a2:b1 ) 01:38:14 (GMT) [ 15 64 49 ] # ( ) 0001 00000040 100 20 6 +N 47.7028750 W 91.0082767 ( default ) BSS ( 0f:0f:3d:00:d2:3f ) 01:39:23 (GMT) [ 25 74 49 ] # ( ) 0421 00000040 100 540 6 +N 47.7118350 W 91.0108833 ( McKee ) BSS ( 0f:0c:41:74:6b:96 ) 01:49:38 (GMT) [ 15 64 49 ] # ( ) 0431 00000008 100 540 3 +N 47.7117300 W 91.0109350 ( airport ) BSS ( 0f:0a:95:f2:aa:0e ) 02:22:33 (GMT) [ 16 65 49 ] # ( ) 0011 00000400 100 540 10 +N 47.7116383 W 91.0109933 ( merv ) BSS ( 0f:06:25:f0:e0:85 ) 02:22:36 (GMT) [ 26 75 49 ] # ( ) 0005 00000040 100 110 6 +N 47.7109717 W 91.0113083 ( home network ) BSS ( 0f:0f:66:2d:d0:bf ) 02:22:45 (GMT) [ 16 65 49 ] # ( ) 0001 00000040 100 540 6 +N 47.7108867 W 91.0113450 ( ) BSS ( 0f:02:2d:2b:81:cf ) 02:22:55 (GMT) [ 13 62 49 ] # ( ) 0011 00000002 100 110 1 +N 47.7107717 W 91.0115567 ( wifi ) BSS ( 0f:40:96:43:5b:9d ) 02:23:02 (GMT) [ 15 64 49 ] # ( ) 0001 00000040 100 20 6 +N 47.7144783 W 91.0139767 ( dsppower ) BSS ( 0f:06:25:f7:6c:c9 ) 02:32:40 (GMT) [ 22 71 49 ] # ( ) 0401 00000040 100 540 6 +N 47.7144567 W 91.0140100 ( linksys ) BSS ( 0f:0c:41:3e:1a:e8 ) 02:32:41 (GMT) [ 15 64 49 ] # ( ) 0005 00000040 100 110 6 +N 47.7182617 W 90.9985767 ( CAMELOT ) BSS ( 0f:06:25:05:24:3d ) 02:44:44 (GMT) [ 25 74 49 ] # ( ) 0011 00000040 100 110 6 +N 47.7181417 W 90.9975217 ( linksys ) BSS ( 0f:0c:41:b6:fe:62 ) 02:44:44 (GMT) [ 16 65 49 ] # ( ) 0005 00000040 100 110 6 +N 47.7182317 W 90.9979867 ( linksys ) BSS ( 0f:0c:41:74:d0:76 ) 02:44:48 (GMT) [ 21 70 49 ] # ( ) 0401 00000002 100 540 1 +N 47.7182467 W 90.9981417 ( house_net ) BSS ( 0f:0f:66:0b:cf:0f ) 02:44:49 (GMT) [ 18 67 49 ] # ( ) 0411 00000004 100 540 2 +N 47.7182600 W 90.9982917 ( NETGEAR ) BSS ( 0f:09:5b:6f:a7:88 ) 02:44:53 (GMT) [ 19 68 49 ] # ( ) 0005 00000800 100 110 11 +N 47.7182467 W 90.9987167 ( linksys ) BSS ( 0f:0c:41:43:87:14 ) 02:44:53 (GMT) [ 22 71 49 ] # ( ) 0005 00000040 100 110 6 +N 47.7178833 W 90.9989217 ( Richard ) ad-hoc ( 4a:e2:7d:43:b0:49 ) 02:45:06 (GMT) [ 20 69 49 ] # ( ) 0422 00000040 100 540 6 +N 47.7179900 W 90.9988900 ( Wireless ) BSS ( 0f:09:5b:39:ae:a2 ) 02:45:06 (GMT) [ 17 66 49 ] # ( ) 0001 00000800 100 110 11 +N 47.7178833 W 90.9989217 ( Nordge ) BSS ( 0f:0d:88:ea:b7:24 ) 02:45:08 (GMT) [ 21 70 49 ] # ( ) 0431 00000040 100 540 6 +# $DateGMT: 2004-06-06 +N 47.7133767 W 91.0131567 ( tom ) BSS ( 0f:06:25:60:6c:b1 ) 03:26:38 (GMT) [ 43 92 49 ] # ( ) 0001 00000800 50 20 11 +N 47.7133767 W 91.0131567 ( default ) BSS ( 0f:0d:88:86:cf:c9 ) 03:26:38 (GMT) [ 14 63 49 ] # ( ) 0041 00000040 100 220 6 +N 47.7133767 W 91.0131567 ( JJ ) BSS ( 0f:60:1d:f6:90:40 ) 03:26:38 (GMT) [ 14 63 49 ] # ( ) 0011 00000002 100 110 1 +N 47.7085167 W 91.0134633 ( purell ) BSS ( 0f:0c:41:bc:2b:00 ) 03:32:42 (GMT) [ 20 69 49 ] # ( ) 0005 00000040 100 110 6 +N 47.7105983 W 91.0111967 ( Wireless ) BSS ( 0f:30:ab:16:7e:50 ) 03:38:38 (GMT) [ 27 76 49 ] # ( ) 0001 00000002 100 110 1 diff --git a/reference/ozi.wpt b/reference/ozi.wpt new file mode 100644 index 000000000..5b3f02df7 --- /dev/null +++ b/reference/ozi.wpt @@ -0,0 +1,13 @@ +OziExplorer Waypoint File Version 1.1 +WGS 84 +Reserved 2 +Reserved 3 +1,GCEBB,35.972033,-87.134700,25569.00000,0,1,3,0,65535,Mountain Bike Heaven by susy1313,0,0,0,0,6,0,17 +2,GC1A37,36.090683,-86.679550,25569.00000,0,1,3,0,65535,The Troll by a182pilot & Family,0,0,0,0,6,0,17 +3,GC1C2B,35.996267,-86.620117,25569.00000,0,1,3,0,65535,Dive Bomber by JoGPS & family,0,0,0,0,6,0,17 +4,GC25A9,36.038483,-86.648617,25569.00000,0,1,3,0,65535,FOSTER by JoGPS & Family,0,0,0,0,6,0,17 +5,GC2723,36.112183,-86.741767,25569.00000,0,1,3,0,65535,Logan Lighthouse by JoGps & Family,0,0,0,0,6,0,17 +6,GC2B71,36.064083,-86.790517,25569.00000,0,1,3,0,65535,Ganier Cache by Susy1313,0,0,0,0,6,0,17 +7,GC309F,36.087767,-86.809733,25569.00000,0,1,3,0,65535,Shy's Hill by FireFighterEng33,0,0,0,0,6,0,17 +8,GC317A,36.057500,-86.892000,25569.00000,0,1,3,0,65535,GittyUp by JoGPS / Warner Parks,0,0,0,0,6,0,17 +9,GC317D,36.082800,-86.867283,25569.00000,0,1,3,0,65535,Inlighting by JoGPS / Warner Parks,0,0,0,0,6,0,17 diff --git a/reference/paris.wpo b/reference/paris.wpo new file mode 100644 index 0000000000000000000000000000000000000000..d9f4252630887f6087828fdb26568ddfe242c889 GIT binary patch literal 25600 zcmeI4OKenS6vzJ;9~40;QXdqnR|`0WQaaO?7A)XA+L@L+x3}Nic9<4aG%?1wFm5$! z&=})_jffg0VPS~TAexAa8W&>X3!;gy7&jUcj0qtzF5H-?=h9NXW4|-QN?n}0=}q&S zlXHIOd}r>=V$w$jcJIZ#06Z+hWw;zy;7Tk;6PDmAEX6Whjcc$R%~*kJu@Wt~4%g!b z+=x|Z#cJGyHr$L`;Nw=@hIXvMTCBtENTCDku>qafh%RhGH`2(U2fgUSX7pnKTd);( zU=Z7|9XoI*vdAHi0){Y*B1#y+D0U)186n0HVH^e(#F)S&s@R1ZrZA1&*n_)pH}1h- zdZ__5@LwCCO`_NT%RsNc@H#i*A=Q6|rsZO;9^GbR6BjB$+J41L#GX!zY{q71h#kp@ zY>&-;Kx})D$g;FQBDN&Q?X%;)KwcGg55esk283non= zD6-n59OhV7+e*s!s3V6tmen>y>?1PEW~TwmW~V_8wcOZ5QYDpH3+u*>(%rVReSwEg z$DEz7ElQ_zV@cS^L?tu+81S+;Gk+hkDIqR-U`aerwf!O17FK8TPKDJD-(N*>e{uMY#!Ng^ zFzh{c5$*N29cMG5$FrQtvmDmY*?iw|Hs@F-;z45f%PbSIm)PfImYugQV(*jLn%(8q z#Lft8J}9!8^hfD=(y>dD+DyQA>dWMJ+R?W;mU&3#tW9Q_2eEInIWP|mShjZ>us%xc;9+c--*0HIzvAcxJ#U8eVXs7K&R>b&hg{C+ z*>t#Kit`}dyhXdO;L3M2EQMy6wc}uYmbK&Q`Ydb5;rc9VM}r*L*=)e(%*1SwIg_f2 z>{zy7`%3O#mwHSr6Gm(s_2Pb4FNkHri2Z^*tQA-$jMyKDZ4p=|jMyKEZFaG7A;{C9 z5i)=MX*|5=c+WC%Pzhp_p9ksYkl^9sw-I`$2GoEWPy=c}4X6P%pa#@{8c+jjKn*s{)rL>GjulpWn7S;=|$hjR*Zrqy$CcxIV&f5W_#QGu_o;SI*6ikf_t>MFPZrXy0MtM3cIXUSvhm-;d)tO?2L^0 zByZ}z&!4^Nh@f>a^kT4y7iVR31Wm=t*YlL%)5ChTTu!>N?k!UL&Fb#YjUGpcz1puI zLk-$d^fOBaI?`0CqDSp9sj7KWd4ta-Qsv$CC@VEe-xkvlbx*h_@~J&Af5Q=hnXQ%m zL=#7+hhc{n3|7{zU_2`TjFPu SM$kFN@9pCq%m2o@IPV{1U$R{Q literal 0 HcmV?d00001 diff --git a/reference/psitwpts.txt b/reference/psitwpts.txt new file mode 100644 index 000000000..27465e721 --- /dev/null +++ b/reference/psitwpts.txt @@ -0,0 +1,17 @@ + 55.205241, -2.556468, 188.78, 001 , wpt_dot + 53.618556, -1.972446,********, 003 , wpt_dot + 53.451544, -1.373673, 166.19, 004 , wpt_dot + 43.621861, -79.378357, 91.21, 005 , wpt_dot + 49.191132,-123.114769, -12.37, 006 , wpt_dot + 49.191140,-123.114736, -0.11, 007 , wpt_dot + 51.285499,-116.946531, 769.42, 008 , wpt_dot + 52.034985, 1.124766,********, BB HOTEL, lodging + 53.895060, -2.611549, 134.71, FELL FOOT, parking + 49.171600,-122.956700,********, FRASERWAY, truck_stop + 51.094100,-114.010600,********, FRASERWYC, truck_stop + 46.538170, 12.124091, 1288.04, OLIMPIA, lodging + 53.900310, -2.618355, 414.45, PARLICK TO, glider + 53.859022, -2.335425, 436.80, PENDLE TO, glider + 51.047100,-114.081900,********, SANDMANC, lodging + 49.189300,-123.112200,********, SANDMANV, lodging + 54.601136, -3.137685,********, SICKWRNG, shpng_cart diff --git a/reference/quovadis.gpu b/reference/quovadis.gpu new file mode 100644 index 000000000..e4c2304fc --- /dev/null +++ b/reference/quovadis.gpu @@ -0,0 +1,9 @@ +GC1A37 3605.441N 08640.773W 0000000m GC1A37 a +GC1C2B 3559.776N 08637.207W 0000000m GC1C2B a +GC25A9 3602.309N 08638.917W 0000000m GC25A9 a +GC2723 3606.731N 08644.506W 0000000m GC2723 a +GC2B71 3603.845N 08647.431W 0000000m GC2B71 a +GC309F 3605.266N 08648.584W 0000000m GC309F a +GC317A 3603.450N 08653.520W 0000000m GC317A a +GC317D 3604.968N 08652.037W 0000000m GC317D a +GCEBB 3558.322N 08708.082W 0000000m GCEBB a diff --git a/reference/quovadis.pdb b/reference/quovadis.pdb new file mode 100644 index 0000000000000000000000000000000000000000..d0d3971b920a4be6c446869b31abac392f7cd6bf GIT binary patch literal 601 zcmWG6%@0dV$t?CwEXqzTa&cln2OJEHyH)#rK^R>sFw8e7Fw{Q`F3tpGB|v$JK$;VX z-JJ~`jm@EgSSZ&1uT0El(_J7^Li{i#Kz+_en9hMoGq6s$tIce|A&RNb$kfpit_*|0 zIwAKuvw5-(7JcSM#u&=s0<8UvKbg&(J+SC=GB<=P!(g!XId?Og{l{XTv4N!%|VC~tiz-%t@1gk!1C}U^>3b6KyuVFUZCV;8W)d^2D QFtBzqi!fWH?L*fG09dLqb^rhX literal 0 HcmV?d00001 diff --git a/reference/radius.csv b/reference/radius.csv new file mode 100644 index 000000000..4095cad3e --- /dev/null +++ b/reference/radius.csv @@ -0,0 +1 @@ +35.97203, -87.13470, Mountain Bike Heaven by susy1313 diff --git a/reference/route/magellan.rte b/reference/route/magellan.rte new file mode 100644 index 000000000..6ded2831b --- /dev/null +++ b/reference/route/magellan.rte @@ -0,0 +1,22 @@ +$PMGNWPL,3042.000,N,09224.000,W,0000000,M,49B,,a*01 +$PMGNWPL,3012.000,N,09218.000,W,0000000,M,49A,,a*08 +$PMGNWPL,2924.000,N,09212.000,W,0000000,M,48B,,a*0D +$PMGNWPL,2900.000,N,09154.000,W,0000000,M,48A,,a*09 +$PMGNWPL,2824.000,N,09124.000,W,0000000,M,47B,,a*05 +$PMGNWPL,2748.000,N,09106.000,W,0000000,M,47A,,a*03 +$PMGNWPL,2636.000,N,09018.000,W,0000000,M,46A,,a*04 +$PMGNWPL,2424.000,N,08824.000,W,0000000,M,43A,,a*06 +$PMGNWPL,2336.000,N,08712.000,W,0000000,M,42A,,a*09 +$PMGNWPL,2300.000,N,08536.000,W,0000000,M,41A,,a*0B +$PMGNWPL,2218.000,N,08424.000,W,0000000,M,40A,,a*00 +$PMGNRTE,6,1,c,1,49B,a,49A,a*01 +$PMGNRTE,6,2,c,1,48B,a,48A,a*02 +$PMGNRTE,6,3,c,1,47B,a,47A,a*03 +$PMGNRTE,6,4,c,1,46A,a,43A,a*02 +$PMGNRTE,6,5,c,1,42A,a,41A,a*05 +$PMGNRTE,6,6,c,1,40A,a,*0D +$PMGNWPL,3016.831,N,09141.153,W,0000000,M,ATLAUN,Launch at Butte LaRose,i*15 +$PMGNWPL,3017.463,N,09137.630,W,0000000,M,ATWRNC,Canal to Warner Lake,k*38 +$PMGNWPL,3018.883,N,09138.767,W,0000000,M,ATWRNR,Warner Lake,a*78 +$PMGNRTE,2,1,c,2,ATLAUN,i,ATWRNC,k*19 +$PMGNRTE,2,2,c,2,ATWRNR,a,*47 diff --git a/reference/route/psitrtes.txt b/reference/route/psitrtes.txt new file mode 100644 index 000000000..96c9fe42d --- /dev/null +++ b/reference/route/psitrtes.txt @@ -0,0 +1,8 @@ +Route: RTE 2 + 57.000000, 5.000000, 100.10, Y1 , wpt_dot + 57.001000, 5.000000, 104.91, Y2 , restrooms + 57.002000, 5.000000, 109.96, Y3 , wpt_dot + 57.003000, 5.001000, 115.00, Y4 , wpt_dot +Route: X1 + 57.000000, 5.000000, 7.10, X11 , wpt_dot + 57.001000, 5.000000, -0.11, X12 , wpt_dot diff --git a/reference/route/route.gpx b/reference/route/route.gpx new file mode 100644 index 000000000..b8d58a158 --- /dev/null +++ b/reference/route/route.gpx @@ -0,0 +1,77 @@ + + + + +LILI PATH +Hurricane LILI + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + + +ATCHAFALAYA +ROUTE1 +1 + +0.000000 + + + + +0.000000 + + + + +0.000000 + + + + + diff --git a/reference/route/route.mapsend b/reference/route/route.mapsend new file mode 100644 index 0000000000000000000000000000000000000000..bd65116929f26f0189e10880e9151875e3edb1b5 GIT binary patch literal 922 zcmZ9L%TB^T6o!xD1yI6SXyV;u<7n1Sd<-=V@yA|Pdt#xd6m!bBs_ zVO(Vm2-Adt==%4e(hYm7f|Qsh4MZ>ZI#jw^cSR7FDQO_lrvDmM1X*NC8A#M1h^v$Z zDKMoCB-(7CaFYm#!!(7txuaYVE!Qup32yov9MH5t$pLkG((k;yhwACe|Lkv9LA4qO zHOdH;9#HMeY-iy$RK@eVjf>qss-eXWJATZ~|Fqvi^>8-3cXe1*P?_>~{GI$EH|uht zSBMV*g`*cSv`^5FM{MU3R6IDhO(S5K)}{XWm7wgwuMYlMMZmCXyOf~BaA_Nqz-1V; zy-Bdh@MhbRpun(YJCeX*IEqRQ&CnD#YjxgYpWBRAgU!aeV9R!tj3vR5Z6+OM4g7Mp G5Bdd#XZxH0 literal 0 HcmV?d00001 diff --git a/reference/route/route.mps b/reference/route/route.mps new file mode 100644 index 0000000000000000000000000000000000000000..e3e78ba88f9412943cb14b13f7d1ac55d1c94dbc GIT binary patch literal 3182 zcma)-KWGzi6vy91Iyv-@ITVTz=;W4M5^IZ4epf9Gp3$bMp@6Q5!{?a92^|# zsFSm}h)Y%KPzSe)h`0!fC~j_2>+flQ-g|lQ@@~o9_kQ2s=iVjxeotO)b(f(40LNBf z)PK0OXnxMYsqVE>l9ZBixdN5?WUW3~twPt|@3?m67MlKS_t+r^0A4Izyd57p@Mb*< zOL{H;Z-fOspSzq+t2v$DA()+ioT<4x@vY5wl*287Go0_j&T>vG*CnU^@NT@ku+_sM zmcSXwcVTBs{;HGK$}U$WW&Zw$!S7doZG_E$8-m=2QBfI>2hI+C{9U39YA`YqmGN|H zbLjfB?U!LQKL<4gxz8L`m9hG1arn~lG0LC@Bjd2jcz^!e$o7TT&%|ff!rOT#LLL6{J}%4nQIN@ z>Rn|sxSgQ-?uXEDv=s zzQxwx^dDxutV?EDs)AE~Zc=Iy$N;Z=_kdua<}`$6BU499UO^fC=9QriC4zT9ykvpd zE#c-L9O4>;tPjajBXc8T3+ocU%JrcRZjOKdMDW4%Df#55C*~>mWTt17WaO6?r$S9A zC`NU*k(0UM#p$UGGd6`fEZSsx(SQSHf`ofwUMA4R&WXuD?*rW(j2v3V29|E$%!{vG z+8pZ8;BN5P0v=j&!5Nk6#R?vokl=F5EJ}3)xgxd5H80&564u6s=8hk_m6nU`40VY7 zDk>hy4zpF>J+q{wGPD5UVSR=0#G*W)Ljn?uvWvlC4b<*Z?4q`{aeJu4wd3!Vrg6cv QD|zPSfGo?*OUG>j0EY0qIRF3v literal 0 HcmV?d00001 diff --git a/reference/track/chi-mapsend.trk b/reference/track/chi-mapsend.trk new file mode 100644 index 0000000000000000000000000000000000000000..1de24286192b3e42f6e78ac4a21ce576f73daa23 GIT binary patch literal 58030 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%0A^M>ugv^`%+^!3~SUdCGUf=Y@$iQ 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 W^yI#^Su>RHy>V_)X)07&7XA;Asx}({ literal 0 HcmV?d00001 diff --git a/reference/track/i65.anr.gpx b/reference/track/i65.anr.gpx new file mode 100644 index 000000000..d0a4f7973 --- /dev/null +++ b/reference/track/i65.anr.gpx @@ -0,0 +1,4971 @@ + + + + + + + \00000 + + + \00001 + + + \00002 + + + \00003 + + + \00004 + + + \00005 + + + \00006 + + + \00007 + + + \00008 + + + \00009 + + + \0000a + + + \0000b + + + \0000c + + + \0000d + + + \0000e + + + \0000f + + + \00010 + + + \00011 + + + \00012 + + + \00013 + + + \00014 + + + \00015 + + + \00016 + + + \00017 + + + \00018 + + + \00019 + + + \0001a + + + \0001b + + + \0001c + + + \0001d + + + \0001e + + + \0001f + + + \00020 + + + \00021 + + + \00022 + + + \00023 + + + \00024 + + + \00025 + + + \00026 + + + \00027 + + + \00028 + + + \00029 + + + \0002a + + + \0002b + + + \0002c + + + \0002d + + + \0002e + + + \0002f + + + \00030 + + + \00031 + + + \00032 + + + \00033 + + + \00034 + + + \00035 + + + \00036 + + + \00037 + + + \00038 + + + \00039 + + + \0003a + + + \0003b + + + \0003c + + + \0003d + + + \0003e + + + \0003f + + + \00040 + + + \00041 + + + \00042 + + + \00043 + + + \00044 + + + \00045 + + + \00046 + + + \00047 + + + \00048 + + + \00049 + + + \0004a + + + \0004b + + + \0004c + + + \0004d + + + \0004e + + + \0004f + + + \00050 + + + \00051 + + + \00052 + + + \00053 + + + \00054 + + + \00055 + + + \00056 + + + \00057 + + + \00058 + + + \00059 + + + \0005a + + + \0005b + + + \0005c + + + \0005d + + + \0005e + + + \0005f + + + \00060 + + + \00061 + + + \00062 + + + \00063 + + + \00064 + + + \00065 + + + \00066 + + + \00067 + + + \00068 + + + \00069 + + + \0006a + + + \0006b + + + \0006c + + + \0006d + + + \0006e + + + \0006f + + + \00070 + + + \00071 + + + \00072 + + + \00073 + + + \00074 + + + \00075 + + + \00076 + + + \00077 + + + \00078 + + + \00079 + + + \0007a + + + \0007b + + + \0007c + + + \0007d + + + \0007e + + + \0007f + + + \00080 + + + \00081 + + + \00082 + + + \00083 + + + \00084 + + + \00085 + + + \00086 + + + \00087 + + + \00088 + + + \00089 + + + \0008a + + + \0008b + + + \0008c + + + \0008d + + + \0008e + + + \0008f + + + \00090 + + + \00091 + + + \00092 + + + \00093 + + + \00094 + + + \00095 + + + \00096 + + + \00097 + + + \00098 + + + \00099 + + + \0009a + + + \0009b + + + \0009c + + + \0009d + + + \0009e + + + \0009f + + + \000a0 + + + \000a1 + + + \000a2 + + + \000a3 + + + \000a4 + + + \000a5 + + + \000a6 + + + \000a7 + + + \000a8 + + + \000a9 + + + \000aa + + + \000ab + + + \000ac + + + \000ad + + + \000ae + + + \000af + + + \000b0 + + + \000b1 + + + \000b2 + + + \000b3 + + + \000b4 + + + \000b5 + + + \000b6 + + + \000b7 + + + \000b8 + + + \000b9 + + + \000ba + + + \000bb + + + \000bc + + + \000bd + + + \000be + + + \000bf + + + \000c0 + + + \000c1 + + + \000c2 + + + \000c3 + + + \000c4 + + + \000c5 + + + \000c6 + + + \000c7 + + + \000c8 + + + \000c9 + + + \000ca + + + \000cb + + + \000cc + + + \000cd + + + \000ce + + + \000cf + + + \000d0 + + + \000d1 + + + \000d2 + + + \000d3 + + + \000d4 + + + \000d5 + + + \000d6 + + + \000d7 + + + \000d8 + + + \000d9 + + + \000da + + + \000db + + + \000dc + + + \000dd + + + \000de + + + \000df + + + \000e0 + + + \000e1 + + + \000e2 + + + \000e3 + + + \000e4 + + + \000e5 + + + \000e6 + + + \000e7 + + + \000e8 + + + \000e9 + + + \000ea + + + \000eb + + + \000ec + + + \000ed + + + \000ee + + + \000ef + + + \000f0 + + + \000f1 + + + \000f2 + + + \000f3 + + + \000f4 + + + \000f5 + + + \000f6 + + + \000f7 + + + \000f8 + + + \000f9 + + + \000fa + + + \000fb + + + \000fc + + + \000fd + + + \000fe + + + \000ff + + + \00100 + + + \00101 + + + \00102 + + + \00103 + + + \00104 + + + \00105 + + + \00106 + + + \00107 + + + \00108 + + + \00109 + + + \0010a + + + \0010b + + + \0010c + + + \0010d + + + \0010e + + + \0010f + + + \00110 + + + \00111 + + + \00112 + + + \00113 + + + \00114 + + + \00115 + + + \00116 + + + \00117 + + + \00118 + + + \00119 + + + \0011a + + + \0011b + + + \0011c + + + \0011d + + + \0011e + + + \0011f + + + \00120 + + + \00121 + + + \00122 + + + \00123 + + + \00124 + + + \00125 + + + \00126 + + + \00127 + + + \00128 + + + \00129 + + + \0012a + + + \0012b + + + \0012c + + + \0012d + + + \0012e + + + \0012f + + + \00130 + + + \00131 + + + \00132 + + + \00133 + + + \00134 + + + \00135 + + + \00136 + + + \00137 + + + \00138 + + + \00139 + + + \0013a + + + \0013b + + + \0013c + + + \0013d + + + \0013e + + + \0013f + + + \00140 + + + \00141 + + + \00142 + + + \00143 + + + \00144 + + + \00145 + + + \00146 + + + \00147 + + + \00148 + + + \00149 + + + \0014a + + + \0014b + + + \0014c + + + \0014d + + + \0014e + + + \0014f + + + \00150 + + + \00151 + + + \00152 + + + \00153 + + + \00154 + + + \00155 + + + \00156 + + + \00157 + + + \00158 + + + \00159 + + + \0015a + + + \0015b + + + \0015c + + + \0015d + + + \0015e + + + \0015f + + + \00160 + + + \00161 + + + \00162 + + + \00163 + + + \00164 + + + \00165 + + + \00166 + + + \00167 + + + \00168 + + + \00169 + + + \0016a + + + \0016b + + + \0016c + + + \0016d + + + \0016e + + + \0016f + + + \00170 + + + \00171 + + + \00172 + + + \00173 + + + \00174 + + + \00175 + + + \00176 + + + \00177 + + + \00178 + + + \00179 + + + \0017a + + + \0017b + + + \0017c + + + \0017d + + + \0017e + + + \0017f + + + \00180 + + + \00181 + + + \00182 + + + \00183 + + + \00184 + + + \00185 + + + \00186 + + + \00187 + + + \00188 + + + \00189 + + + \0018a + + + \0018b + + + \0018c + + + \0018d + + + \0018e + + + \0018f + + + \00190 + + + \00191 + + + \00192 + + + \00193 + + + \00194 + + + \00195 + + + \00196 + + + \00197 + + + \00198 + + + \00199 + + + \0019a + + + \0019b + + + \0019c + + + \0019d + + + \0019e + + + \0019f + + + \001a0 + + + \001a1 + + + \001a2 + + + \001a3 + + + \001a4 + + + \001a5 + + + \001a6 + + + \001a7 + + + \001a8 + + + \001a9 + + + \001aa + + + \001ab + + + \001ac + + + \001ad + + + \001ae + + + \001af + + + \001b0 + + + \001b1 + + + \001b2 + + + \001b3 + + + \001b4 + + + \001b5 + + + \001b6 + + + \001b7 + + + \001b8 + + + \001b9 + + + \001ba + + + \001bb + + + \001bc + + + \001bd + + + \001be + + + \001bf + + + \001c0 + + + \001c1 + + + \001c2 + + + \001c3 + + + \001c4 + + + \001c5 + + + \001c6 + + + \001c7 + + + \001c8 + + + \001c9 + + + \001ca + + + \001cb + + + \001cc + + + \001cd + + + \001ce + + + \001cf + + + \001d0 + + + \001d1 + + + \001d2 + + + \001d3 + + + \001d4 + + + \001d5 + + + \001d6 + + + \001d7 + + + \001d8 + + + \001d9 + + + \001da + + + \001db + + + \001dc + + + \001dd + + + \001de + + + \001df + + + \001e0 + + + \001e1 + + + \001e2 + + + \001e3 + + + \001e4 + + + \001e5 + + + \001e6 + + + \001e7 + + + \001e8 + + + \001e9 + + + \001ea + + + \001eb + + + \001ec + + + \001ed + + + \001ee + + + \001ef + + + \001f0 + + + \001f1 + + + \001f2 + + + \001f3 + + + \001f4 + + + \001f5 + + + \001f6 + + + \001f7 + + + \001f8 + + + \001f9 + + + \001fa + + + \001fb + + + \001fc + + + \001fd + + + \001fe + + + \001ff + + + \00200 + + + \00201 + + + \00202 + + + \00203 + + + \00204 + + + \00205 + + + \00206 + + + \00207 + + + \00208 + + + \00209 + + + \0020a + + + \0020b + + + \0020c + + + \0020d + + + \0020e + + + \0020f + + + \00210 + + + \00211 + + + \00212 + + + \00213 + + + \00214 + + + \00215 + + + \00216 + + + \00217 + + + \00218 + + + \00219 + + + \0021a + + + \0021b + + + \0021c + + + \0021d + + + \0021e + + + \0021f + + + \00220 + + + \00221 + + + \00222 + + + \00223 + + + \00224 + + + \00225 + + + \00226 + + + \00227 + + + \00228 + + + \00229 + + + \0022a + + + \0022b + + + \0022c + + + \0022d + + + \0022e + + + \0022f + + + \00230 + + + \00231 + + + \00232 + + + \00233 + + + \00234 + + + \00235 + + + \00236 + + + \00237 + + + \00238 + + + \00239 + + + \0023a + + + \0023b + + + \0023c + + + \0023d + + + \0023e + + + \0023f + + + \00240 + + + \00241 + + + \00242 + + + \00243 + + + \00244 + + + \00245 + + + \00246 + + + \00247 + + + \00248 + + + \00249 + + + \0024a + + + \0024b + + + \0024c + + + \0024d + + + \0024e + + + \0024f + + + \00250 + + + \00251 + + + \00252 + + + \00253 + + + \00254 + + + \00255 + + + \00256 + + + \00257 + + + \00258 + + + \00259 + + + \0025a + + + \0025b + + + \0025c + + + \0025d + + + \0025e + + + \0025f + + + \00260 + + + \00261 + + + \00262 + + + \00263 + + + \00264 + + + \00265 + + + \00266 + + + \00267 + + + \00268 + + + \00269 + + + \0026a + + + \0026b + + + \0026c + + + \0026d + + + \0026e + + + \0026f + + + \00270 + + + \00271 + + + \00272 + + + \00273 + + + \00274 + + + \00275 + + + \00276 + + + \00277 + + + \00278 + + + \00279 + + + \0027a + + + \0027b + + + \0027c + + + \0027d + + + \0027e + + + \0027f + + + \00280 + + + \00281 + + + \00282 + + + \00283 + + + \00284 + + + \00285 + + + \00286 + + + \00287 + + + \00288 + + + \00289 + + + \0028a + + + \0028b + + + \0028c + + + \0028d + + + \0028e + + + \0028f + + + \00290 + + + \00291 + + + \00292 + + + \00293 + + + \00294 + + + \00295 + + + \00296 + + + \00297 + + + \00298 + + + \00299 + + + \0029a + + + \0029b + + + \0029c + + + \0029d + + + \0029e + + + \0029f + + + \002a0 + + + \002a1 + + + \002a2 + + + \002a3 + + + \002a4 + + + \002a5 + + + \002a6 + + + \002a7 + + + \002a8 + + + \002a9 + + + \002aa + + + \002ab + + + \002ac + + + \002ad + + + \002ae + + + \002af + + + \002b0 + + + \002b1 + + + \002b2 + + + \002b3 + + + \002b4 + + + \002b5 + + + \002b6 + + + \002b7 + + + \002b8 + + + \002b9 + + + \002ba + + + \002bb + + + \002bc + + + \002bd + + + \002be + + + \002bf + + + \002c0 + + + \002c1 + + + \002c2 + + + \002c3 + + + \002c4 + + + \002c5 + + + \002c6 + + + \002c7 + + + \002c8 + + + \002c9 + + + \002ca + + + \002cb + + + \002cc + + + \002cd + + + \002ce + + + \002cf + + + \002d0 + + + \002d1 + + + \002d2 + + + \002d3 + + + \002d4 + + + \002d5 + + + \002d6 + + + \002d7 + + + \002d8 + + + \002d9 + + + \002da + + + \002db + + + \002dc + + + \002dd + + + \002de + + + \002df + + + \002e0 + + + \002e1 + + + \002e2 + + + \002e3 + + + \002e4 + + + \002e5 + + + \002e6 + + + \002e7 + + + \002e8 + + + \002e9 + + + \002ea + + + \002eb + + + \002ec + + + \002ed + + + \002ee + + + \002ef + + + \002f0 + + + \002f1 + + + \002f2 + + + \002f3 + + + \002f4 + + + \002f5 + + + \002f6 + + + \002f7 + + + \002f8 + + + \002f9 + + + \002fa + + + \002fb + + + \002fc + + + \002fd + + + \002fe + + + \002ff + + + \00300 + + + \00301 + + + \00302 + + + \00303 + + + \00304 + + + \00305 + + + \00306 + + + \00307 + + + \00308 + + + \00309 + + + \0030a + + + \0030b + + + \0030c + + + \0030d + + + \0030e + + + \0030f + + + \00310 + + + \00311 + + + \00312 + + + \00313 + + + \00314 + + + \00315 + + + \00316 + + + \00317 + + + \00318 + + + \00319 + + + \0031a + + + \0031b + + + \0031c + + + \0031d + + + \0031e + + + \0031f + + + \00320 + + + \00321 + + + \00322 + + + \00323 + + + \00324 + + + \00325 + + + \00326 + + + \00327 + + + \00328 + + + \00329 + + + \0032a + + + \0032b + + + \0032c + + + \0032d + + + \0032e + + + \0032f + + + \00330 + + + \00331 + + + \00332 + + + \00333 + + + \00334 + + + \00335 + + + \00336 + + + \00337 + + + \00338 + + + \00339 + + + \0033a + + + \0033b + + + \0033c + + + \0033d + + + \0033e + + + \0033f + + + \00340 + + + \00341 + + + \00342 + + + \00343 + + + \00344 + + + \00345 + + + \00346 + + + \00347 + + + \00348 + + + \00349 + + + \0034a + + + \0034b + + + \0034c + + + \0034d + + + \0034e + + + \0034f + + + \00350 + + + \00351 + + + \00352 + + + \00353 + + + \00354 + + + \00355 + + + \00356 + + + \00357 + + + \00358 + + + \00359 + + + \0035a + + + \0035b + + + \0035c + + + \0035d + + + \0035e + + + \0035f + + + \00360 + + + \00361 + + + \00362 + + + \00363 + + + \00364 + + + \00365 + + + \00366 + + + \00367 + + + \00368 + + + \00369 + + + \0036a + + + \0036b + + + \0036c + + + \0036d + + + \0036e + + + \0036f + + + \00370 + + + \00371 + + + \00372 + + + \00373 + + + \00374 + + + \00375 + + + \00376 + + + \00377 + + + \00378 + + + \00379 + + + \0037a + + + \0037b + + + \0037c + + + \0037d + + + \0037e + + + \0037f + + + \00380 + + + \00381 + + + \00382 + + + \00383 + + + \00384 + + + \00385 + + + \00386 + + + \00387 + + + \00388 + + + \00389 + + + \0038a + + + \0038b + + + \0038c + + + \0038d + + + \0038e + + + \0038f + + + \00390 + + + \00391 + + + \00392 + + + \00393 + + + \00394 + + + \00395 + + + \00396 + + + \00397 + + + \00398 + + + \00399 + + + \0039a + + + \0039b + + + \0039c + + + \0039d + + + \0039e + + + \0039f + + + \003a0 + + + \003a1 + + + \003a2 + + + \003a3 + + + \003a4 + + + \003a5 + + + \003a6 + + + \003a7 + + + \003a8 + + + \003a9 + + + \003aa + + + \003ab + + + \003ac + + + \003ad + + + \003ae + + + \003af + + + \003b0 + + + \003b1 + + + \003b2 + + + \003b3 + + + \003b4 + + + \003b5 + + + \003b6 + + + \003b7 + + + \003b8 + + + \003b9 + + + \003ba + + + \003bb + + + \003bc + + + \003bd + + + \003be + + + \003bf + + + \003c0 + + + \003c1 + + + \003c2 + + + \003c3 + + + \003c4 + + + \003c5 + + + \003c6 + + + \003c7 + + + \003c8 + + + \003c9 + + + \003ca + + + \003cb + + + \003cc + + + \003cd + + + \003ce + + + \003cf + + + \003d0 + + + \003d1 + + + \003d2 + + + \003d3 + + + \003d4 + + + \003d5 + + + \003d6 + + + \003d7 + + + \003d8 + + + \003d9 + + + \003da + + + \003db + + + \003dc + + + \003dd + + + \003de + + + \003df + + + \003e0 + + + \003e1 + + + \003e2 + + + \003e3 + + + \003e4 + + + \003e5 + + + \003e6 + + + \003e7 + + + \003e8 + + + \003e9 + + + \003ea + + + \003eb + + + \003ec + + + \003ed + + + \003ee + + + \003ef + + + \003f0 + + + \003f1 + + + \003f2 + + + \003f3 + + + \003f4 + + + \003f5 + + + \003f6 + + + \003f7 + + + \003f8 + + + \003f9 + + + \003fa + + + \003fb + + + \003fc + + + \003fd + + + \003fe + + + \003ff + + + \00400 + + + \00401 + + + \00402 + + + \00403 + + + \00404 + + + \00405 + + + \00406 + + + \00407 + + + \00408 + + + \00409 + + + \0040a + + + \0040b + + + \0040c + + + \0040d + + + \0040e + + + \0040f + + + \00410 + + + \00411 + + + \00412 + + + \00413 + + + \00414 + + + \00415 + + + \00416 + + + \00417 + + + \00418 + + + \00419 + + + \0041a + + + \0041b + + + \0041c + + + \0041d + + + \0041e + + + \0041f + + + \00420 + + + \00421 + + + \00422 + + + \00423 + + + \00424 + + + \00425 + + + \00426 + + + \00427 + + + \00428 + + + \00429 + + + \0042a + + + \0042b + + + \0042c + + + \0042d + + + \0042e + + + \0042f + + + \00430 + + + \00431 + + + \00432 + + + \00433 + + + \00434 + + + \00435 + + + \00436 + + + \00437 + + + \00438 + + + \00439 + + + \0043a + + + \0043b + + + \0043c + + + \0043d + + + \0043e + + + \0043f + + + \00440 + + + \00441 + + + \00442 + + + \00443 + + + \00444 + + + \00445 + + + \00446 + + + \00447 + + + \00448 + + + \00449 + + + \0044a + + + \0044b + + + \0044c + + + \0044d + + + \0044e + + + \0044f + + + \00450 + + + \00451 + + + \00452 + + + \00453 + + + \00454 + + + \00455 + + + \00456 + + + \00457 + + + \00458 + + + \00459 + + + \0045a + + + \0045b + + + \0045c + + + \0045d + + + \0045e + + + \0045f + + + \00460 + + + \00461 + + + \00462 + + + \00463 + + + \00464 + + + \00465 + + + \00466 + + + \00467 + + + \00468 + + + \00469 + + + \0046a + + + \0046b + + + \0046c + + + \0046d + + + \0046e + + + \0046f + + + \00470 + + + \00471 + + + \00472 + + + \00473 + + + \00474 + + + \00475 + + + \00476 + + + \00477 + + + \00478 + + + \00479 + + + \0047a + + + \0047b + + + \0047c + + + \0047d + + + \0047e + + + \0047f + + + \00480 + + + \00481 + + + \00482 + + + \00483 + + + \00484 + + + \00485 + + + \00486 + + + \00487 + + + \00488 + + + \00489 + + + \0048a + + + \0048b + + + \0048c + + + \0048d + + + \0048e + + + \0048f + + + \00490 + + + \00491 + + + \00492 + + + \00493 + + + \00494 + + + \00495 + + + \00496 + + + \00497 + + + \00498 + + + \00499 + + + \0049a + + + \0049b + + + \0049c + + + \0049d + + + \0049e + + + \0049f + + + \004a0 + + + \004a1 + + + \004a2 + + + \004a3 + + + \004a4 + + + \004a5 + + + \004a6 + + + \004a7 + + + \004a8 + + + \004a9 + + + \004aa + + + \004ab + + + \004ac + + + \004ad + + + \004ae + + + \004af + + + \004b0 + + + \004b1 + + + \004b2 + + + \004b3 + + + \004b4 + + + \004b5 + + + \004b6 + + + \004b7 + + + \004b8 + + + \004b9 + + + \004ba + + + \004bb + + + \004bc + + + \004bd + + + \004be + + + \004bf + + + \004c0 + + + \004c1 + + + \004c2 + + + \004c3 + + + \004c4 + + + \004c5 + + + \004c6 + + + \004c7 + + + \004c8 + + + \004c9 + + + \004ca + + + \004cb + + + \004cc + + + \004cd + + + \004ce + + + \004cf + + + \004d0 + + + \004d1 + + + \004d2 + + + \004d3 + + + \004d4 + + + \004d5 + + + \004d6 + + + \004d7 + + + \004d8 + + + \004d9 + + + \004da + + + \004db + + + \004dc + + + \004dd + + + \004de + + + \004df + + + \004e0 + + + \004e1 + + + \004e2 + + + \004e3 + + + \004e4 + + + \004e5 + + + \004e6 + + + \004e7 + + + \004e8 + + + \004e9 + + + \004ea + + + \004eb + + + \004ec + + + \004ed + + + \004ee + + + \004ef + + + \004f0 + + + \004f1 + + + \004f2 + + + \004f3 + + + \004f4 + + + \004f5 + + + \004f6 + + + \004f7 + + + \004f8 + + + \004f9 + + + \004fa + + + \004fb + + + \004fc + + + \004fd + + + \004fe + + + \004ff + + + \00500 + + + \00501 + + + \00502 + + + \00503 + + + \00504 + + + \00505 + + + \00506 + + + \00507 + + + \00508 + + + \00509 + + + \0050a + + + \0050b + + + \0050c + + + \0050d + + + \0050e + + + \0050f + + + \00510 + + + \00511 + + + \00512 + + + \00513 + + + \00514 + + + \00515 + + + \00516 + + + \00517 + + + \00518 + + + \00519 + + + \0051a + + + \0051b + + + \0051c + + + \0051d + + + \0051e + + + \0051f + + + \00520 + + + \00521 + + + \00522 + + + \00523 + + + \00524 + + + \00525 + + + \00526 + + + \00527 + + + \00528 + + + \00529 + + + \0052a + + + \0052b + + + \0052c + + + \0052d + + + \0052e + + + \0052f + + + \00530 + + + \00531 + + + \00532 + + + \00533 + + + \00534 + + + \00535 + + + \00536 + + + \00537 + + + \00538 + + + \00539 + + + \0053a + + + \0053b + + + \0053c + + + \0053d + + + \0053e + + + \0053f + + + \00540 + + + \00541 + + + \00542 + + + \00543 + + + \00544 + + + \00545 + + + \00546 + + + \00547 + + + \00548 + + + \00549 + + + \0054a + + + \0054b + + + \0054c + + + \0054d + + + \0054e + + + \0054f + + + \00550 + + + \00551 + + + \00552 + + + \00553 + + + \00554 + + + \00555 + + + \00556 + + + \00557 + + + \00558 + + + \00559 + + + \0055a + + + \0055b + + + \0055c + + + \0055d + + + \0055e + + + \0055f + + + \00560 + + + \00561 + + + \00562 + + + \00563 + + + \00564 + + + \00565 + + + \00566 + + + \00567 + + + \00568 + + + \00569 + + + \0056a + + + \0056b + + + \0056c + + + \0056d + + + \0056e + + + \0056f + + + \00570 + + + \00571 + + + \00572 + + + \00573 + + + \00574 + + + \00575 + + + \00576 + + + \00577 + + + \00578 + + + \00579 + + + \0057a + + + \0057b + + + \0057c + + + \0057d + + + \0057e + + + \0057f + + + \00580 + + + \00581 + + + \00582 + + + \00583 + + + \00584 + + + \00585 + + + \00586 + + + \00587 + + + \00588 + + + \00589 + + + \0058a + + + \0058b + + + \0058c + + + \0058d + + + \0058e + + + \0058f + + + \00590 + + + \00591 + + + \00592 + + + \00593 + + + \00594 + + + \00595 + + + \00596 + + + \00597 + + + \00598 + + + \00599 + + + \0059a + + + \0059b + + + \0059c + + + \0059d + + + \0059e + + + \0059f + + + \005a0 + + + \005a1 + + + \005a2 + + + \005a3 + + + \005a4 + + + \005a5 + + + \005a6 + + + \005a7 + + + \005a8 + + + \005a9 + + + \005aa + + + \005ab + + + \005ac + + + \005ad + + + \005ae + + + \005af + + + \005b0 + + + \005b1 + + + \005b2 + + + \005b3 + + + \005b4 + + + \005b5 + + + \005b6 + + + \005b7 + + + \005b8 + + + \005b9 + + + \005ba + + + \005bb + + + \005bc + + + \005bd + + + \005be + + + \005bf + + + \005c0 + + + \005c1 + + + \005c2 + + + \005c3 + + + \005c4 + + + \005c5 + + + \005c6 + + + \005c7 + + + \005c8 + + + \005c9 + + + \005ca + + + \005cb + + + \005cc + + + \005cd + + + \005ce + + + \005cf + + + \005d0 + + + \005d1 + + + \005d2 + + + \005d3 + + + \005d4 + + + \005d5 + + + \005d6 + + + \005d7 + + + \005d8 + + + \005d9 + + + \005da + + + \005db + + + \005dc + + + \005dd + + + \005de + + + \005df + + + \005e0 + + + \005e1 + + + \005e2 + + + \005e3 + + + \005e4 + + + \005e5 + + + \005e6 + + + \005e7 + + + \005e8 + + + \005e9 + + + \005ea + + + \005eb + + + \005ec + + + \005ed + + + \005ee + + + \005ef + + + \005f0 + + + \005f1 + + + \005f2 + + + \005f3 + + + \005f4 + + + \005f5 + + + \005f6 + + + \005f7 + + + \005f8 + + + \005f9 + + + \005fa + + + \005fb + + + \005fc + + + \005fd + + + \005fe + + + \005ff + + + \00600 + + + \00601 + + + \00602 + + + \00603 + + + \00604 + + + \00605 + + + \00606 + + + \00607 + + + \00608 + + + \00609 + + + \0060a + + + \0060b + + + \0060c + + + \0060d + + + \0060e + + + \0060f + + + \00610 + + + \00611 + + + \00612 + + + \00613 + + + \00614 + + + \00615 + + + \00616 + + + \00617 + + + \00618 + + + \00619 + + + \0061a + + + \0061b + + + \0061c + + + \0061d + + + \0061e + + + \0061f + + + \00620 + + + \00621 + + + \00622 + + + \00623 + + + \00624 + + + \00625 + + + \00626 + + + \00627 + + + \00628 + + + \00629 + + + \0062a + + + \0062b + + + \0062c + + + \0062d + + + \0062e + + + \0062f + + + \00630 + + + \00631 + + + \00632 + + + \00633 + + + \00634 + + + \00635 + + + \00636 + + + \00637 + + + \00638 + + + \00639 + + + \0063a + + + \0063b + + + \0063c + + + \0063d + + + \0063e + + + \0063f + + + \00640 + + + \00641 + + + \00642 + + + \00643 + + + \00644 + + + \00645 + + + \00646 + + + \00647 + + + \00648 + + + \00649 + + + \0064a + + + \0064b + + + \0064c + + + \0064d + + + \0064e + + + \0064f + + + \00650 + + + \00651 + + + \00652 + + + \00653 + + + \00654 + + + \00655 + + + \00656 + + + \00657 + + + \00658 + + + \00659 + + + \0065a + + + \0065b + + + \0065c + + + \0065d + + + \0065e + + + \0065f + + + \00660 + + + \00661 + + + \00662 + + + \00663 + + + \00664 + + + \00665 + + + \00666 + + + \00667 + + + \00668 + + + \00669 + + + \0066a + + + \0066b + + + \0066c + + + \0066d + + + \0066e + + + \0066f + + + \00670 + + + \00671 + + + \00672 + + + \00673 + + + \00674 + + + diff --git a/reference/track/mapsend.trk b/reference/track/mapsend.trk new file mode 100644 index 0000000000000000000000000000000000000000..6ce0351c876bacdf9c78a8e6e85af222c35b70b9 GIT binary patch literal 1884 zcmZA1doWyQ6aet0@v5+kN(3vZ5LzjVRjS)W9!OH_S=-c#M@b?|8c95&m^>=OM7q@y zBhjsiiP6?n^Qt^-vP6-H!J?J~yHz@AOC&8VG1BwJIWwmBpSyE^d(Qdp_nmu8gj>Bl z;S#P9M|cW#IUJ7Odk5naKJtTK{(%Q)xxY!28a?lge{eS_b>P|Q=Eov-=h(de=1B{{ z!ab*o&3PM?>{-H3h-)1~`zOXF%Foi%Y)lX}gc8r4F(ZIRcK0o&AuWsKwP0jpOz=zt zU{|1iwG#0dp(wb!I2zFF#MrbL(Y6&M4eNGr1%QXHT0UzxT}fBK9U(@F_@uV0M~1FUF#I#-RDLs)uR+nfy8xhibX z2GcsJu;!<{+{8G*>__X|4FTDK77-d*9r$J!;2v9^=_sbXM`)W9?-2>;XAys=2ap}I zc@L(IC=c1P3D9S{q;41^iwL>ng>&A3$u2WxLx>8(3ghh&uLG|BcE!RhqHZsyHM^i_ zTnRYmKK{KUzDgcpV!l@m5AcWEuvPdfHH7n1t1|Qe1%|b@QGjf$^FCV<+z) z&p_n&VaS*SZ<$tjp2wQ8gxi|FQ@sQ@(E_`SHCqX_k&krr0euJlvgcr%{6i?e zmt*}h;Eh)=SMm`Ze#V-F9g}zOY)1Tm@QS2$85bfiSG{WdZ~i3PTdmYT26fN6d{MIR$72^)s4U2+H9XP=Ul z4ftY;3}V{M>Lz7aPx&YZG^bt0R z!k!2GFOvTNYi?y1V4dTyC*+tmjWDn9)Q|4~?pjuvn2)F>Y+XC-Bm_)#57$jcw0nqY z#lH13E`R~fRrR|Og9)u3&eyI66nhtLibE_UTr=0Edy?N$y)(I^mqi=1) zNTVUFneP@<&ARX3bWMdBVho`HOm71~ZTaZqC)n`?ga@j08rX*<%lf)Yjd+RB`kdhK zbC_TqZ^Ph4rr4dBQ$ zgq7BAL#&5tc;{uyF_JfeHQPO!FS-K$U3~1dDV!z&ge&-W$2J0X7N~|bh^2&<{`P@l zz@_t6O(=8Sp2cQgPuaDk2N=oKU`?ykPimq7mrk%S!sPUzDK>BW*$0KIEhYR9HcXdG literal 0 HcmV?d00001 diff --git a/reference/track/meridian.trk b/reference/track/meridian.trk new file mode 100644 index 000000000..abcb1a40a --- /dev/null +++ b/reference/track/meridian.trk @@ -0,0 +1,64 @@ +$PMGNTRK,3003.731,N,09136.621,W,00001,M,170621.25,A,,250502*6A +$PMGNTRK,3003.767,N,09136.634,W,00000,M,170955.19,A,,250502*6F +$PMGNTRK,3003.762,N,09136.496,W,00000,M,171200.20,A,,250502*60 +$PMGNTRK,3003.740,N,09136.443,W,00000,M,171248.75,A,,250502*64 +$PMGNTRK,3003.692,N,09136.317,W,00000,M,171441.20,A,,250502*63 +$PMGNTRK,3003.587,N,09135.964,W,00000,M,171716.20,A,,250502*68 +$PMGNTRK,3003.468,N,09135.801,W,00000,M,171746.20,A,,250502*6F +$PMGNTRK,3003.323,N,09135.694,W,00000,M,171820.81,A,,250502*61 +$PMGNTRK,3003.233,N,09135.557,W,00000,M,171901.20,A,,250502*64 +$PMGNTRK,3002.984,N,09135.385,W,00000,M,172046.25,A,,250502*67 +$PMGNTRK,3002.941,N,09135.393,W,00000,M,172110.25,A,,250502*6B +$PMGNTRK,3002.928,N,09135.576,W,00000,M,172151.37,A,,250502*6F +$PMGNTRK,3002.774,N,09135.787,W,00000,M,172235.20,A,,250502*63 +$PMGNTRK,3002.731,N,09135.923,W,00000,M,172308.56,A,,250502*6C +$PMGNTRK,3002.838,N,09136.016,W,00000,M,180423.93,A,,250502*6C +$PMGNTRK,3002.820,N,09135.978,W,00002,M,180604.92,A,,250502*63 +$PMGNTRK,3002.786,N,09135.968,W,00000,M,180706.92,A,,250502*60 +$PMGNTRK,3002.772,N,09135.937,W,00001,M,180818.92,A,,250502*60 +$PMGNTRK,3002.782,N,09135.864,W,00000,M,181020.92,A,,250502*6B +$PMGNTRK,3002.781,N,09135.830,W,00000,M,181109.93,A,,250502*62 +$PMGNTRK,3002.807,N,09135.780,W,00000,M,181218.92,A,,250502*65 +$PMGNTRK,3002.847,N,09135.712,W,00000,M,181422.93,A,,250502*64 +$PMGNTRK,3002.868,N,09135.686,W,00002,M,181504.93,A,,250502*62 +$PMGNTRK,3002.895,N,09135.645,W,00001,M,181614.93,A,,250502*6E +$PMGNTRK,3002.921,N,09135.628,W,00001,M,181701.93,A,,250502*6E +$PMGNTRK,3002.961,N,09135.631,W,00000,M,181807.94,A,,250502*6D +$PMGNTRK,3003.019,N,09135.639,W,00002,M,181951.94,A,,250502*62 +$PMGNTRK,3003.047,N,09135.647,W,00000,M,182039.94,A,,250502*66 +$PMGNTRK,3003.074,N,09135.662,W,00000,M,182124.93,A,,250502*6B +$PMGNTRK,3003.108,N,09135.662,W,00000,M,182217.94,A,,250502*65 +$PMGNTRK,3003.133,N,09135.680,W,00000,M,182318.93,A,,250502*68 +$PMGNTRK,3003.181,N,09135.681,W,00000,M,182437.94,A,,250502*6D +$PMGNTRK,3003.292,N,09135.712,W,00006,M,182813.95,A,,250502*6A +$PMGNTRK,3003.224,N,09135.696,W,00002,M,183136.94,A,,250502*60 +$PMGNTRK,3003.191,N,09135.687,W,00000,M,183256.95,A,,250502*6B +$PMGNTRK,3003.158,N,09135.690,W,00000,M,183402.95,A,,250502*6F +$PMGNTRK,3003.147,N,09135.726,W,00000,M,183603.95,A,,250502*6E +$PMGNTRK,3003.149,N,09135.758,W,00000,M,183648.96,A,,250502*65 +$PMGNTRK,3003.159,N,09135.807,W,00001,M,183752.96,A,,250502*6A +$PMGNTRK,3003.188,N,09135.871,W,00000,M,183918.95,A,,250502*65 +$PMGNTRK,3003.217,N,09135.878,W,00000,M,184015.96,A,,250502*69 +$PMGNTRK,3003.238,N,09135.866,W,00006,M,184125.96,A,,250502*6F +$PMGNTRK,3003.217,N,09135.885,W,00000,M,184237.96,A,,250502*69 +$PMGNTRK,3003.192,N,09135.875,W,00000,M,184401.96,A,,250502*6B +$PMGNTRK,3003.169,N,09135.851,W,00000,M,184553.96,A,,250502*6F +$PMGNTRK,3003.154,N,09135.816,W,00000,M,184654.96,A,,250502*66 +$PMGNTRK,3003.140,N,09135.786,W,00000,M,184742.97,A,,250502*62 +$PMGNTRK,3003.135,N,09135.741,W,00000,M,184841.96,A,,250502*66 +$PMGNTRK,3003.133,N,09135.701,W,00000,M,184952.97,A,,250502*66 +$PMGNTRK,3003.113,N,09135.682,W,00000,M,185049.97,A,,250502*6C +$PMGNTRK,3003.063,N,09135.664,W,00000,M,185214.97,A,,250502*68 +$PMGNTRK,3003.034,N,09135.654,W,00000,M,185256.98,A,,250502*60 +$PMGNTRK,3003.011,N,09135.646,W,00000,M,185338.98,A,,250502*6D +$PMGNTRK,3002.946,N,09135.623,W,00000,M,185511.97,A,,250502*66 +$PMGNTRK,3002.907,N,09135.655,W,00000,M,185632.98,A,,250502*6F +$PMGNTRK,3002.885,N,09135.685,W,00000,M,185724.97,A,,250502*60 +$PMGNTRK,3002.850,N,09135.727,W,00007,M,185840.98,A,,250502*64 +$PMGNTRK,3002.824,N,09135.760,W,00000,M,185928.98,A,,250502*6C +$PMGNTRK,3002.798,N,09135.796,W,00000,M,190022.98,A,,250502*6A +$PMGNTRK,3002.784,N,09135.859,W,00000,M,190141.98,A,,250502*6F +$PMGNTRK,3002.774,N,09135.908,W,00000,M,190248.99,A,,250502*6E +$PMGNTRK,3002.779,N,09135.938,W,00000,M,190343.98,A,,250502*6B +$PMGNTRK,3002.807,N,09135.957,W,00000,M,190449.99,A,,250502*68 +$PMGNTRK,3002.828,N,09135.980,W,00000,M,190557.98,A,,250502*60 diff --git a/reference/track/mps-track.mps b/reference/track/mps-track.mps new file mode 100644 index 0000000000000000000000000000000000000000..9889d176a9e0d4a4a0da4960e88a8cd7714bb9f8 GIT binary patch literal 2056 zcmZA2X-HI26bJD8#%RSd<%s2iiKIlD8X}{iW2hLBrI{#s?|V5GQbC(VgbB8xVNHvM z_#r}CjBHGUpg>Jr#?-8|Y;;_a3N@_!U<;wW5qk5lfyco7-Z}p}?_SQ^b}Yr1&2)^h zxNPRBe#Hh$JCkGCc4Mw@Scq?^Uax1NVUgh>ksCL%SBn@+O+C8Dcz{Xjt<0caTka_o zYwfR}|ADcuG18^xFPrQ-|A}c*D6mUo#w244FmF&OU2pqat?~$Rf?1(6S;#J}P(53y zkkX7?fP6SYAye-FH21PVwazBfx?O|7k;qy5WlE?-&O|=tFViE}A*eo&>}C{{ScW`> zToo&5R@>3_~Z?&=k^_Ayr9Kz9EvNUlZx zfSi;f<3sf@NOkWaJI`CDr*|FI2C2{rY;%(7$wLP-$%?F>5R~-*d37IDn@0s5Fd<(@ zjv5nm^#t;BWHu?NV28%)hO&NWenFC{!$)Iv$I_6UJ!HyUg=|9343x?2r?L82-XYto zKf7tHHuttccEtj9cz7ZoL2jNFlp2gYitO`A(77$hJ_FD^dO*;df2Knca;8;K%UP^0 zLbjil-U{T`$nh3IWi`l41|j>$O3u1NKm>3xe$5TNkOKU$hF9(ctHn;kyi{s zc3gmZ99oeTmq8jq?)=Ef>A1$~hPn(xc6m1^=M3Zofn!REKvh7oG&W4 + + + + + +1.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +2.000000 + + + +0.000000 + + + +1.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +2.000000 + + + +1.000000 + + + +1.000000 + + + +0.000000 + + + +2.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +6.000000 + + + +2.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +1.000000 + + + +0.000000 + + + +0.000000 + + + +6.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +7.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + +0.000000 + + + + + diff --git a/reference/track/webpark1.gpl b/reference/track/webpark1.gpl new file mode 100644 index 0000000000000000000000000000000000000000..6fd866a1939092ba3abc1779bacc60eda602d146 GIT binary patch literal 54656 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 +#include "defs.h" + +#define MYNAME "Route reversal filter" + +static +arglist_t reverse_route_args[] = { + {0, 0, 0, 0, 0} +}; + +void +reverse_route_head( const route_head *rte ) +{ + route_reverse(rte); +} + +void +reverse_route_process( void ) +{ + route_disp_all( reverse_route_head, NULL, NULL ); +} + +void +reverse_route_init(const char *args) +{ + switch (global_opts.objective) { + case rtedata: break; + case trkdata: break; + default: + fatal(MYNAME ": This filter only works in track " + "or route (-t or -r) mode."); + } +} + +void +reverse_route_deinit(void) +{ + /* do nothing */ +} + +filter_vecs_t reverse_route_vecs = { + reverse_route_init, + reverse_route_process, + reverse_route_deinit, + NULL, + reverse_route_args +}; diff --git a/route.c b/route.c new file mode 100644 index 000000000..0f0733087 --- /dev/null +++ b/route.c @@ -0,0 +1,197 @@ +/* + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include "defs.h" + +static queue my_route_head; +static queue my_track_head; +static int rte_head_ct; +static int rte_waypts; +static int trk_head_ct; + +void +route_init(void) +{ + QUEUE_INIT(&my_route_head); + QUEUE_INIT(&my_track_head); +} + +unsigned int +route_waypt_count(void) +{ + /* total wapoint count -- all routes */ + return rte_waypts; +} + +unsigned int +route_count(void) +{ + return rte_head_ct; /* total # of routes */ +} + +unsigned int +track_count(void) +{ + return trk_head_ct; /* total # of tracks */ +} + +route_head * +route_head_alloc(void) +{ + route_head *rte_head; + rte_head = (route_head *) xcalloc(sizeof (*rte_head), 1); + QUEUE_INIT(&rte_head->Q); + return rte_head; +} + + +void +route_add_head(route_head *rte) +{ + ENQUEUE_TAIL(&my_route_head, &rte->Q); + QUEUE_INIT(&rte->waypoint_list); + rte_head_ct++; +} + +void +route_del_head(route_head *rte) +{ + dequeue( &rte->Q ); + route_free( rte ); + rte_head_ct--; +} + +void +track_add_head(route_head *rte) +{ + ENQUEUE_TAIL(&my_track_head, &rte->Q); + QUEUE_INIT(&rte->waypoint_list); + trk_head_ct++; +} + +void +track_del_head(route_head *rte) +{ + dequeue( &rte->Q ); + route_free( rte ); + trk_head_ct--; +} + +void +route_add_wpt(route_head *rte, waypoint *wpt) +{ + ENQUEUE_TAIL(&rte->waypoint_list, &wpt->Q); + rte->rte_waypt_ct++; /* waypoints in this route */ + rte_waypts++; /* total waypoints in all routes */ +} + +void +route_del_wpt( route_head *rte, waypoint *wpt) +{ + dequeue( &wpt->Q ); + waypt_free( wpt ); + rte->rte_waypt_ct--; + rte_waypts--; +} + +void +route_free(route_head *rte) +{ + if ( rte->rte_name ) { + xfree(rte->rte_name); + } + if ( rte->rte_desc ) { + xfree(rte->rte_desc); + } + rte_waypts -= rte->rte_waypt_ct; + waypt_flush(&rte->waypoint_list); + xfree(rte); +} + +void +route_disp (const route_head *rh, waypt_cb cb ) +{ + queue *elem, *tmp; + if (!cb) { + return; + } + QUEUE_FOR_EACH(&rh->waypoint_list, elem, tmp) { + waypoint *waypointp; + waypointp = (waypoint *) elem; + (*cb)(waypointp); + } + +} + +void +route_reverse(const route_head *rte_hd) +{ + /* Cast away const-ness */ + route_head *rh = (route_head *) rte_hd; + queue *elem, *tmp; + QUEUE_FOR_EACH(&rh->waypoint_list, elem, tmp) { + ENQUEUE_HEAD(&rh->waypoint_list, dequeue(elem)); + } +} + +void +common_disp_all(queue *qh, route_hdr rh, route_trl rt, waypt_cb wc) +{ + queue *elem, *tmp; + QUEUE_FOR_EACH(qh, elem, tmp) { + const route_head *rhp; + rhp = (route_head *) elem; + if (rh) (*rh)(rhp); + route_disp(rhp, wc); + if (rt) (*rt)(rhp); + } +} + +void +route_disp_all(route_hdr rh, route_trl rt, waypt_cb wc) +{ + common_disp_all(&my_route_head, rh, rt, wc); +} + +void +track_disp_all(route_hdr rh, route_trl rt, waypt_cb wc) +{ + common_disp_all(&my_track_head, rh, rt, wc); +} + +void +route_flush(queue *head) +{ + queue *elem, *tmp; + queue *q; + + QUEUE_FOR_EACH(head, elem, tmp) { + q = dequeue(elem); + route_free((route_head *) q); + } +} + +void +route_flush_all() +{ + route_flush(&my_route_head); + route_flush(&my_track_head); +} + diff --git a/saroute.c b/saroute.c new file mode 100644 index 000000000..23152112e --- /dev/null +++ b/saroute.c @@ -0,0 +1,281 @@ +/* + Read various Delorme routes including anr, rte, and rtd. + + Copyright (C) 2003 Ron Parker and Robert Lipe. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include +#include + +#define MYNAME "saroute" +#include "defs.h" + +FILE *infile; + +char *turns_important = NULL; +char *turns_only = NULL; + +static +arglist_t saroute_args[] = { + {"turns_important", &turns_important, + "Keep turns if simplify filter is used", + NULL, ARGTYPE_BOOL }, + {"turns_only", &turns_only, "Only read turns; skip all other points", + NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0 } +}; + +unsigned short +ReadShort(FILE * f) +{ + unsigned short result = 0; + + fread(&result, sizeof (result), 1, f); + return le_read16(&result); +} + +unsigned long +ReadLong(FILE * f) +{ + unsigned long result = 0; + + fread(&result, sizeof (result), 1, f); + return le_read32(&result); +} + +unsigned char * +ReadRecord(FILE * f, + unsigned long size) +{ + unsigned char *result = (unsigned char *) xmalloc(size); + + fread(result, size, 1, f); + return result; +} + +void +Skip(FILE * f, + unsigned long distance) +{ + fseek(f, distance, SEEK_CUR); +} + +static void +rd_init(const char *fname) +{ + infile = xfopen(fname, "rb", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(infile); +} + +static void +my_read(void) +{ + + unsigned short version; + unsigned long count; + unsigned long outercount; + unsigned long recsize; + unsigned short stringlen; + unsigned char *record; + static int serial = 0; + struct ll { + long lat; + long lon; + } *latlon; + unsigned short coordcount; + route_head *track_head; + waypoint *wpt_tmp; + + ReadShort(infile); /* magic */ + version = ReadShort(infile); + + ReadLong(infile); + if (version >= 6) { + ReadLong(infile); + ReadLong(infile); + } + + /* + * end of header + */ + + ReadShort(infile); + recsize = ReadLong(infile); + /* + * the first recsize, oddly, doesn't include the filename string + * but it does include the header. + */ + record = ReadRecord(infile, recsize); + + stringlen = le_read16((unsigned short *)(record + 0x1a)); + Skip(infile, stringlen - 4); + xfree(record); + + /* + * end of filename record + */ + + /* + * here lie the route description records + */ + if ( version < 6 ) { + track_head = route_head_alloc(); + route_add_head(track_head); + } + count = ReadLong(infile); + while (count) { + ReadShort(infile); + recsize = ReadLong(infile); + if (version < 6) { + double lat; + double lon; + + record = ReadRecord(infile, recsize); + latlon = (struct ll *)(record); + + lat = (0x80000000UL - + le_read32(&latlon->lat)) / (double)(0x800000); + lon = (0x80000000UL - + le_read32(&latlon->lon)) / (double)(0x800000); + + wpt_tmp = waypt_new(); + wpt_tmp->latitude = lat; + wpt_tmp->longitude = -lon; + wpt_tmp->shortname = (char *) xmalloc(7); + sprintf( wpt_tmp->shortname, "\\%5.5x", serial++ ); + route_add_wpt(track_head, wpt_tmp); + xfree(record); + } else { + Skip(infile, recsize); + /* + * two longs of scrap after each record, don't know why + */ + ReadLong(infile); + ReadLong(infile); + } + count--; + } + /* + * end of route desc records + */ + + /* + * outercount is the number of route segments (start+end+stops+vias-1) + */ + + outercount = ReadLong(infile); + while (outercount) { + + /* + * unknown record (route params?) lives here + */ + ReadShort(infile); + recsize = ReadLong(infile); + Skip(infile, recsize); + + /* + * end of unknown record + */ + + /* + * routing begins here + */ + count = ReadLong(infile); + if ( count ) { + track_head = route_head_alloc(); + route_add_head(track_head); + } + while (count) { + ReadShort(infile); + recsize = ReadLong(infile); + record = ReadRecord(infile, recsize); + stringlen = le_read16((unsigned short *)record); + coordcount = le_read16((unsigned short *) + (record + 2 + stringlen + 0x3c)); + latlon = (struct ll *)(record + 2 + stringlen + 0x3c + 2); + count--; + if (count) { + coordcount--; + } + while (coordcount) { + double lat; + double lon; + + wpt_tmp = waypt_new(); + + lat = (0x80000000UL - + le_read32(&latlon->lat)) / + (double)(0x800000); + lon = (0x80000000UL - + le_read32(&latlon->lon)) / + (double)(0x800000); + + wpt_tmp->latitude = lat; + wpt_tmp->longitude = -lon; + wpt_tmp->shortname = (char *) xmalloc(7); + if ( turns_important && stringlen ) + wpt_tmp->route_priority=1; + sprintf( wpt_tmp->shortname, "\\%5.5x", + serial++ ); + if ( !turns_only || stringlen ) + route_add_wpt(track_head, wpt_tmp); + + latlon++; + coordcount--; + stringlen = 0; + /* the stop point is a "turn" */ + if ( coordcount == 1 && count == 0 ) { + stringlen = 1; + } + } + if ( version > 10 ) { + Skip(infile,2*sizeof(long)); + } + xfree(record); + } + /* + * end of routing + */ + outercount--; + } + +} + +static void +wr_init(const char *fname) +{ + fatal(MYNAME ":Not enough information is known about this format to write it.\n"); +} + +ff_vecs_t saroute_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + NULL, + my_read, + NULL, + NULL, + saroute_args +}; diff --git a/shape.c b/shape.c new file mode 100644 index 000000000..0da74b97c --- /dev/null +++ b/shape.c @@ -0,0 +1,200 @@ +/* + + ESRI shp/shx shapefiles. + + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include "defs.h" +#include "shapelib/shapefil.h" + +static SHPHandle ihandle; +static DBFHandle ihandledb; +static SHPHandle ohandle; +#define MYNAME "shape" + +static unsigned poly_count; +static double *polybufx; +static double *polybufy; +static double *polybufz; +static const char *ofname; +static int nameidx; + +static void +my_rd_init(const char *fname) +{ + int i; + + ihandle = SHPOpen(fname, "rb" ); + if (ihandle == NULL) { + fatal(MYNAME ":Cannot open shp file %s for reading\n", fname); + } + + ihandledb = DBFOpen(fname, "rb" ); + if (ihandledb == NULL) { + fatal(MYNAME ":Cannot open dbf file %s for reading\n", fname); + } + + nameidx = DBFGetFieldIndex( ihandledb, "NAME" ); + if (nameidx == -1) { +// fatal(MYNAME ":dbf file for %s doesn't have 'NAME'\n", fname); + } +} + +void +my_read(void) +{ + int npts; + + SHPGetInfo(ihandle, &npts, NULL, NULL, NULL); + + while (npts) { + SHPObject *shp; + waypoint *wpt; + const char *name; + + shp = SHPReadObject(ihandle, npts-1); + name = DBFReadStringAttribute(ihandledb, npts-1, nameidx); + if (shp->nSHPType == SHPT_ARC) { + int j; + route_head *track_head = route_head_alloc(); + route_add_head(track_head); + for (j = 0; j < shp->nVertices; j++) { + wpt = waypt_new(); + wpt->latitude = shp->padfY[j]; + wpt->longitude = shp->padfX[j]; + wpt->altitude = shp->padfZ[j]; + route_add_wpt(track_head, wpt); + } + } + + if (shp->nSHPType == SHPT_POINT) { + wpt = waypt_new(); + wpt->latitude = shp->dfYMin; + wpt->longitude = shp->dfXMin; + wpt->shortname = strdup(name); + waypt_add(wpt); + } + + SHPDestroyObject(shp); + + npts--; + } + +} + +void +my_rd_deinit(void) +{ + close (ihandle); +} + +void +my_wr_init(const char *fname) +{ + ofname = fname; +} + +void +my_wr_deinit(void) +{ + SHPClose (ohandle); +} + +void +my_write_wpt(const waypoint *wpt) +{ + SHPObject *shpobject; + + shpobject = SHPCreateSimpleObject(SHPT_POINT, 1, + (double *)(void *)&wpt->longitude, + (double *)(void *)&wpt->latitude, + (double *)(void *)&wpt->altitude); + SHPWriteObject(ohandle, -1, shpobject); + SHPDestroyObject(shpobject); +} + +void +poly_init() +{ + int ct = route_waypt_count(); + polybufx = xcalloc(ct, sizeof(double)); + polybufy = xcalloc(ct, sizeof(double)); + polybufz = xcalloc(ct, sizeof(double)); +} + + +void +poly_point(const waypoint *wpt) +{ + polybufx[poly_count] = wpt->longitude; + polybufy[poly_count] = wpt->latitude; + polybufz[poly_count] = wpt->altitude; + poly_count++; +} + +void +poly_deinit() +{ + SHPObject *shpobject; + shpobject = SHPCreateSimpleObject(SHPT_ARC, route_waypt_count(), + polybufx, polybufy, polybufz); + SHPWriteObject(ohandle, -1, shpobject); + SHPDestroyObject(shpobject); + xfree(polybufx); + xfree(polybufy); + xfree(polybufz); + fprintf(stderr, "Done\n"); + poly_count = 0; +} + + +void +my_write(void) +{ + switch(global_opts.objective) { + case wptdata: + ohandle = SHPCreate(ofname, SHPT_POINT); + + if (ohandle == NULL) { + fatal(MYNAME ":Cannot open %s for writing\n", + ofname); + } + waypt_disp_all(my_write_wpt); + break; + case trkdata: + ohandle = SHPCreate(ofname, SHPT_ARC); + + if (ohandle == NULL) { + fatal(MYNAME ":Cannot open %s for writing\n", + ofname); + } + route_disp_all(poly_init, poly_deinit, poly_point); + break; + } +} + +ff_vecs_t shape_vecs = { + ff_type_internal, + my_rd_init, + my_wr_init, + my_rd_deinit, + my_wr_deinit, + my_read, + my_write, + NULL +}; diff --git a/shapelib/README.GPSBabel b/shapelib/README.GPSBabel new file mode 100644 index 000000000..7961447b0 --- /dev/null +++ b/shapelib/README.GPSBabel @@ -0,0 +1,4 @@ +This is a subset of Shapelib v1.2.10 from http://shapelib.maptools.org/ + +The source is unmodified. It's subsetted here only to reduce the amount of +size in our tree that it takes and to reduce ongoing merge maintenance. diff --git a/shapelib/dbf_api.html b/shapelib/dbf_api.html new file mode 100644 index 000000000..b0fa37372 --- /dev/null +++ b/shapelib/dbf_api.html @@ -0,0 +1,408 @@ + + +Attribute (.DBF) API + + +

Attribute (.DBF) API

+ +The Attribute (DBF) API uses DBFHandle to represent a handle for access +to one .dbf file. The contents of the DBFHandle are visible (see shapefil.h) +but should be ignored by the application. It is intended that all information +be accessed by API functions. Note that there should be exactly one record +in the .dbf file for each shape in the .shp/.shx files. This constraint +must be maintained by the application.

+ + + +

DBFOpen()

+ +
+DBFHandle DBFOpen( const char * pszDBFFile, const char * pszAccess );
+
+  pszDBFFile:		The name of the xBase (.dbf) file to access.
+
+  pszAccess:		The fopen() style access string.  At this time only
+			"rb" (read-only binary) and "rb+" (read/write binary) 
+		        should be used.
+
+ + The DBFOpen() function should be used to establish access to an existing + xBase format table file. The returned DBFHandle is passed to other + access functions, and DBFClose() should be invoked to recover resources, and + flush changes to disk when complete. The DBFCreate() function should + called to create new xBase files. As a convenience, DBFOpen() can be + called with the name of a .shp or .shx file, and it will figure out the + name of the related .dbf file.

+ + + +

DBFCreate()

+ +
+DBFHandle DBFCreate( const char * pszDBFFile );
+
+  pszDBFFile:		The name of the xBase (.dbf) file to create.
+
+ + The DBFCreate() function creates a new xBase format file with the given + name, and returns an access handle that can be used with other DBF functions. + The newly created file will have no fields, and no records. Fields should + be added with DBFAddField() before any records add written. + + + +

DBFGetFieldCount()

+ +
+int DBFGetFieldCount( DBFHandle hDBF );
+
+  hDBF:		The access handle for the file to be queried, as returned
+                by DBFOpen(), or DBFCreate().
+
+ + The DBFGetFieldCount() function returns the number of fields currently + defined for the indicated xBase file. + + + +

DBFGetRecordCount()

+ +
+int DBFGetRecordCount( DBFHandle hDBF );
+
+  hDBF:		The access handle for the file to be queried, as returned by
+		DBFOpen(), or DBFCreate().
+
+ + The DBFGetRecordCount() function returns the number of records that + exist on the xBase file currently. Note that with shape files one xBase + record exists for each shape in the .shp/.shx files.

+ + + +

DBFGetFieldIndex()

+ +
+int DBFGetFieldIndex( DBFHandle hDBF, const char *pszFieldName );
+
+  hDBF:		The access handle for the file to be queried, as returned by
+		DBFOpen(), or DBFCreate().
+
+  pszFieldName: Name of the field to search for.
+
+ + Returns the index of the field matching this name, or -1 on failure. The + comparison is case insensitive. However, lengths must match exactly.

+ + + +

DBFGetFieldInfo()

+ +
+DBFFieldType DBFGetFieldInfo( DBFHandle hDBF, int iField, char * pszFieldName,
+                              int * pnWidth, int * pnDecimals );
+
+  hDBF:		The access handle for the file to be queried, as returned by
+		DBFOpen(), or DBFCreate().
+
+  iField:	The field to be queried.  This should be a number between 
+                0 and n-1, where n is the number fields on the file, as
+                returned by DBFGetFieldCount().
+
+  pszFieldName:	If this pointer is not NULL the name of the requested field
+		will be written to this location.  The pszFieldName buffer 
+                should be at least 12 character is size in order to hold
+		the longest possible field name of 11 characters plus a 
+                terminating zero character.
+
+  pnWidth:	If this pointer is not NULL, the width of the requested field
+		will be returned in the int pointed to by pnWidth.  This is
+                the width in characters.  
+
+  pnDecimals:	If this pointer is not NULL, the number of decimal places
+                precision defined for the field will be returned.  This is
+                zero for integer fields, or non-numeric fields.
+
+ + The DBFGetFieldInfo() returns the type of the requested field, which is + one of the DBFFieldType enumerated values. As well, the field name, and + field width information can optionally be returned. The field type returned + does not correspond one to one with the xBase field types. For instance + the xBase field type for Date will just be returned as being FTInteger.

+ +

+    typedef enum {
+      FTString,			/* fixed length string field 		*/
+      FTInteger,		/* numeric field with no decimals 	*/
+      FTDouble,			/* numeric field with decimals 		*/
+      FTLogical,		/* logical field.                       */
+      FTInvalid                 /* not a recognised field type 		*/
+    } DBFFieldType;
+
+ + + +

DBFAddField()

+ +
+int DBFAddField( DBFHandle hDBF, const char * pszFieldName, 
+                 DBFFieldType eType, int nWidth, int nDecimals );
+
+  hDBF:		The access handle for the file to be updated, as returned by
+		DBFOpen(), or DBFCreate().
+
+  pszFieldName:	The name of the new field.  At most 11 character will be used.
+                In order to use the xBase file in some packages it may be
+                necessary to avoid some special characters in the field names
+                such as spaces, or arithmetic operators.
+
+  eType:	One of FTString, FTInteger or FTDouble in order to establish
+                the type of the new field.  Note that some valid xBase field
+                types cannot be created such as date fields.
+
+  nWidth:	The width of the field to be created.  For FTString fields this
+                establishes the maximum length of string that can be stored.
+                For FTInteger this establishes the number of digits of the
+                largest number that can
+                be represented.  For FTDouble fields this in combination
+                with the nDecimals value establish the size, and precision
+                of the created field.
+
+  nDecimals:    The number of decimal places to reserve for FTDouble fields.
+                For all other field types this should be zero.  For instance
+                with nWidth=7, and nDecimals=3 numbers would be formatted
+                similarly to `123.456'.
+
+ + The DBFAddField() function is used to add new fields to an existing xBase + file opened with DBFOpen(), or created with DBFCreate(). Note that fields + can only be added to xBase files with no records, though this is limitation + of this API, not of the file format.

+ + The DBFAddField() return value is the field number of the new field, or + -1 if the addition of the field failed.

+ + + +

DBFReadIntegerAttribute()

+ +
+int DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );
+  
+  hDBF:		The access handle for the file to be queried, as returned by
+		DBFOpen(), or DBFCreate().
+
+  iShape:	The record number (shape number) from which the field value
+                should be read.
+
+  iField:	The field within the selected record that should be read.
+
+ + The DBFReadIntegerAttribute() will read the value of one field and return + it as an integer. This can be used even with FTString fields, though the + returned value will be zero if not interpretable as a number.

+ + + +

DBFReadDoubleAttribute()

+ +
+double DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
+  
+  hDBF:		The access handle for the file to be queried, as returned by
+		DBFOpen(), or DBFCreate().
+
+  iShape:	The record number (shape number) from which the field value
+                should be read.
+
+  iField:	The field within the selected record that should be read.
+
+ + The DBFReadDoubleAttribute() will read the value of one field and return + it as a double. This can be used even with FTString fields, though the + returned value will be zero if not interpretable as a number.

+ + + +

DBFReadStringAttribute()

+ +
+const char *DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
+  
+  hDBF:		The access handle for the file to be queried, as returned by
+		DBFOpen(), or DBFCreate().
+
+  iShape:	The record number (shape number) from which the field value
+                should be read.
+
+  iField:	The field within the selected record that should be read.
+
+ + The DBFReadStringAttribute() will read the value of one field and return + it as a string. This function may be used on any field type (including + FTInteger and FTDouble) and will return the string representation stored + in the .dbf file. The returned pointer is to an internal buffer + which is only valid untill the next DBF function call. It's contents may + be copied with normal string functions such as strcpy(), or strdup(). If + the TRIM_DBF_WHITESPACE macro is defined in shapefil.h (it is by default) + then all leading and trailing space (ASCII 32) characters will be stripped + before the string is returned.

+ + + +

DBFIsAttributeNULL()

+ +
+int DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField );
+  
+  hDBF:		The access handle for the file to be queried, as returned by
+		DBFOpen(), or DBFCreate().
+
+  iShape:	The record number (shape number) from which the field value
+                should be read.
+
+  iField:	The field within the selected record that should be read.
+
+ + This function will return TRUE if the indicated field is NULL valued + otherwise FALSE. Note that NULL fields are represented in the .dbf file + as having all spaces in the field. Reading NULL fields will result in + a value of 0.0 or an empty string with the other DBFRead*Attribute() + functions.

+ + + +

DBFWriteIntegerAttribute

+ +
+int DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
+                              int nFieldValue );
+
+  hDBF:		The access handle for the file to be written, as returned by
+		DBFOpen(), or DBFCreate().
+
+  iShape:	The record number (shape number) to which the field value
+                should be written.
+
+  iField:	The field within the selected record that should be written.
+
+  nFieldValue:	The integer value that should be written.
+
+ +The DBFWriteIntegerAttribute() function is used to write a value to a numeric +field (FTInteger, or FTDouble). If the write succeeds the value TRUE will +be returned, otherwise FALSE will be returned. If the value is too large to +fit in the field, it will be truncated and FALSE returned.

+ + + +

DBFWriteDoubleAttribute()

+ +
+int DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,
+                             double dFieldValue );
+
+  hDBF:		The access handle for the file to be written, as returned by
+		DBFOpen(), or DBFCreate().
+
+  iShape:	The record number (shape number) to which the field value
+                should be written.
+
+  iField:	The field within the selected record that should be written.
+
+  dFieldValue:	The floating point value that should be written.
+
+ +The DBFWriteDoubleAttribute() function is used to write a value to a numeric +field (FTInteger, or FTDouble). If the write succeeds the value TRUE will +be returned, otherwise FALSE will be returned. If the value is too large to +fit in the field, it will be truncated and FALSE returned.

+ + + +

DBFWriteStringAttribute()

+ +
+int DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField,
+                             const char * pszFieldValue );
+
+  hDBF:		The access handle for the file to be written, as returned by
+		DBFOpen(), or DBFCreate().
+
+  iShape:	The record number (shape number) to which the field value
+                should be written.
+
+  iField:	The field within the selected record that should be written.
+
+  pszFieldValue: The string to be written to the field.
+
+ +The DBFWriteStringAttribute() function is used to write a value to a string +field (FString). If the write succeeds the value TRUE willbe returned, +otherwise FALSE will be returned. If the value is too large to +fit in the field, it will be truncated and FALSE returned.

+ + + +

DBFWriteNULLAttribute()

+ +
+int DBFWriteNULLAttribute( DBFHandle hDBF, int iShape, int iField );
+
+  hDBF:		The access handle for the file to be written, as returned by
+		DBFOpen(), or DBFCreate().
+
+  iShape:	The record number (shape number) to which the field value
+                should be written.
+
+  iField:	The field within the selected record that should be written.
+
+ +The DBFWriteNULLAttribute() function is used to clear the indicated field +to a NULL value. In the .dbf file this is represented by setting the entire +field to spaces. If the write succeeds the value TRUE willbe returned, +otherwise FALSE will be returned.

+ + + +

DBFClose()

+ +
+void DBFClose( DBFHandle hDBF );
+
+  hDBF:		The access handle for the file to be closed.
+
+ + The DBFClose() function will close the indicated xBase file (opened with + DBFOpen(), or DBFCreate()), flushing out all information to the file on + disk, and recovering any resources associated with having the file open. + The file handle (hDBF) should not be used again with the DBF API after + calling DBFClose().

+ + + +

DBFGetNativeFieldType()

+ +
+char DBFGetNativeFieldType( DBFHandle hDBF, int iField );
+
+  hDBF:		The access handle for the file.
+  iField:       The field index to query.
+  
+
+ + This function returns the DBF type code of the indicated field. It will + be one of:

+ +

    +
  • 'C' (String) +
  • 'D' (Date) +
  • 'F' (Float) +
  • 'N' (Numeric, with or without decimal) +
  • 'L' (Logical) +
  • 'M' (Memo: 10 digits .DBT block ptr) +
  • ' ' (field out of range) +
+ + + diff --git a/shapelib/dbfopen.c b/shapelib/dbfopen.c new file mode 100644 index 000000000..a6a0be543 --- /dev/null +++ b/shapelib/dbfopen.c @@ -0,0 +1,1498 @@ +/****************************************************************************** + * $Id: dbfopen.c,v 1.1 2004/09/20 17:21:22 robertl Exp $ + * + * Project: Shapelib + * Purpose: Implementation of .dbf access API documented in dbf_api.html. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 1999, Frank Warmerdam + * + * This software is available under the following "MIT Style" license, + * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This + * option is discussed in more detail in shapelib.html. + * + * -- + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************** + * + * $Log: dbfopen.c,v $ + * Revision 1.1 2004/09/20 17:21:22 robertl + * Check in shapelib and experimental prototype of crude shapefile support. + * + * Revision 1.48 2003/03/10 14:51:27 warmerda + * DBFWrite* calls now return FALSE if they have to truncate + * + * Revision 1.47 2002/11/20 03:32:22 warmerda + * Ensure field name in DBFGetFieldIndex() is properly terminated. + * + * Revision 1.46 2002/10/09 13:10:21 warmerda + * Added check that width is positive. + * + * Revision 1.45 2002/09/29 00:00:08 warmerda + * added FTLogical and logical attribute read/write calls + * + * Revision 1.44 2002/05/07 13:46:11 warmerda + * Added DBFWriteAttributeDirectly(). + * + * Revision 1.43 2002/02/13 19:39:21 warmerda + * Fix casting issues in DBFCloneEmpty(). + * + * Revision 1.42 2002/01/15 14:36:07 warmerda + * updated email address + * + * Revision 1.41 2002/01/15 14:31:49 warmerda + * compute rather than copying nHeaderLength in DBFCloneEmpty() + * + * Revision 1.40 2002/01/09 04:32:35 warmerda + * fixed to read correct amount of header + * + * Revision 1.39 2001/12/11 22:41:03 warmerda + * improve io related error checking when reading header + * + * Revision 1.38 2001/11/28 16:07:31 warmerda + * Cleanup to avoid compiler warnings as suggested by Richard Hash. + * + * Revision 1.37 2001/07/04 05:18:09 warmerda + * do last fix properly + * + * Revision 1.36 2001/07/04 05:16:09 warmerda + * fixed fieldname comparison in DBFGetFieldIndex + * + * Revision 1.35 2001/06/22 02:10:06 warmerda + * fixed NULL shape support with help from Jim Matthews + * + * Revision 1.33 2001/05/31 19:20:13 warmerda + * added DBFGetFieldIndex() + * + * Revision 1.32 2001/05/31 18:15:40 warmerda + * Added support for NULL fields in DBF files + * + * Revision 1.31 2001/05/23 13:36:52 warmerda + * added use of SHPAPI_CALL + * + * Revision 1.30 2000/12/05 14:43:38 warmerda + * DBReadAttribute() white space trimming bug fix + * + * Revision 1.29 2000/10/05 14:36:44 warmerda + * fix bug with writing very wide numeric fields + * + * Revision 1.28 2000/09/25 14:18:07 warmerda + * Added some casts of strlen() return result to fix warnings on some + * systems, as submitted by Daniel. + * + * Revision 1.27 2000/09/25 14:15:51 warmerda + * added DBFGetNativeFieldType() + * + * Revision 1.26 2000/07/07 13:39:45 warmerda + * removed unused variables, and added system include files + * + * Revision 1.25 2000/05/29 18:19:13 warmerda + * avoid use of uchar, and adding casting fix + * + * Revision 1.24 2000/05/23 13:38:27 warmerda + * Added error checks on return results of fread() and fseek(). + * + * Revision 1.23 2000/05/23 13:25:49 warmerda + * Avoid crashing if field or record are out of range in dbfread*attribute(). + * + * Revision 1.22 1999/12/15 13:47:24 warmerda + * Added stdlib.h to ensure that atof() is prototyped. + * + * Revision 1.21 1999/12/13 17:25:46 warmerda + * Added support for upper case .DBF extention. + * + * Revision 1.20 1999/11/30 16:32:11 warmerda + * Use atof() instead of sscanf(). + * + * Revision 1.19 1999/11/05 14:12:04 warmerda + * updated license terms + * + * Revision 1.18 1999/07/27 00:53:28 warmerda + * ensure that whole old field value clear on write of string + * + * Revision 1.1 1999/07/05 18:58:07 warmerda + * New + * + * Revision 1.17 1999/06/11 19:14:12 warmerda + * Fixed some memory leaks. + * + * Revision 1.16 1999/06/11 19:04:11 warmerda + * Remoted some unused variables. + * + * Revision 1.15 1999/05/11 03:19:28 warmerda + * added new Tuple api, and improved extension handling - add from candrsn + * + * Revision 1.14 1999/05/04 15:01:48 warmerda + * Added 'F' support. + * + * Revision 1.13 1999/03/23 17:38:59 warmerda + * DBFAddField() now actually does return the new field number, or -1 if + * it fails. + * + * Revision 1.12 1999/03/06 02:54:46 warmerda + * Added logic to convert shapefile name to dbf filename in DBFOpen() + * for convenience. + * + * Revision 1.11 1998/12/31 15:30:34 warmerda + * Improved the interchangability of numeric and string attributes. Add + * white space trimming option for attributes. + * + * Revision 1.10 1998/12/03 16:36:44 warmerda + * Use r+b instead of rb+ for binary access. + * + * Revision 1.9 1998/12/03 15:34:23 warmerda + * Updated copyright message. + * + * Revision 1.8 1997/12/04 15:40:15 warmerda + * Added newline character after field definitions. + * + * Revision 1.7 1997/03/06 14:02:10 warmerda + * Ensure bUpdated is initialized. + * + * Revision 1.6 1996/02/12 04:54:41 warmerda + * Ensure that DBFWriteAttribute() returns TRUE if it succeeds. + * + * Revision 1.5 1995/10/21 03:15:12 warmerda + * Changed to use binary file access, and ensure that the + * field name field is zero filled, and limited to 10 chars. + * + * Revision 1.4 1995/08/24 18:10:42 warmerda + * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such + * as on the Sun. + * + * Revision 1.3 1995/08/04 03:15:16 warmerda + * Fixed up header. + * + * Revision 1.2 1995/08/04 03:14:43 warmerda + * Added header. + */ + +static char rcsid[] = + "$Id: dbfopen.c,v 1.1 2004/09/20 17:21:22 robertl Exp $"; + +#include "shapefil.h" + +#include +#include +#include +#include + +#ifndef FALSE +# define FALSE 0 +# define TRUE 1 +#endif + +static int nStringFieldLen = 0; +static char * pszStringField = NULL; + +/************************************************************************/ +/* SfRealloc() */ +/* */ +/* A realloc cover function that will access a NULL pointer as */ +/* a valid input. */ +/************************************************************************/ + +static void * SfRealloc( void * pMem, int nNewSize ) + +{ + if( pMem == NULL ) + return( (void *) malloc(nNewSize) ); + else + return( (void *) realloc(pMem,nNewSize) ); +} + +/************************************************************************/ +/* DBFWriteHeader() */ +/* */ +/* This is called to write out the file header, and field */ +/* descriptions before writing any actual data records. This */ +/* also computes all the DBFDataSet field offset/size/decimals */ +/* and so forth values. */ +/************************************************************************/ + +static void DBFWriteHeader(DBFHandle psDBF) + +{ + unsigned char abyHeader[XBASE_FLDHDR_SZ]; + int i; + + if( !psDBF->bNoHeader ) + return; + + psDBF->bNoHeader = FALSE; + +/* -------------------------------------------------------------------- */ +/* Initialize the file header information. */ +/* -------------------------------------------------------------------- */ + for( i = 0; i < XBASE_FLDHDR_SZ; i++ ) + abyHeader[i] = 0; + + abyHeader[0] = 0x03; /* memo field? - just copying */ + + /* date updated on close, record count preset at zero */ + + abyHeader[8] = psDBF->nHeaderLength % 256; + abyHeader[9] = psDBF->nHeaderLength / 256; + + abyHeader[10] = psDBF->nRecordLength % 256; + abyHeader[11] = psDBF->nRecordLength / 256; + +/* -------------------------------------------------------------------- */ +/* Write the initial 32 byte file header, and all the field */ +/* descriptions. */ +/* -------------------------------------------------------------------- */ + fseek( psDBF->fp, 0, 0 ); + fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp ); + fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp ); + +/* -------------------------------------------------------------------- */ +/* Write out the newline character if there is room for it. */ +/* -------------------------------------------------------------------- */ + if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 ) + { + char cNewline; + + cNewline = 0x0d; + fwrite( &cNewline, 1, 1, psDBF->fp ); + } +} + +/************************************************************************/ +/* DBFFlushRecord() */ +/* */ +/* Write out the current record if there is one. */ +/************************************************************************/ + +static void DBFFlushRecord( DBFHandle psDBF ) + +{ + int nRecordOffset; + + if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 ) + { + psDBF->bCurrentRecordModified = FALSE; + + nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord + + psDBF->nHeaderLength; + + fseek( psDBF->fp, nRecordOffset, 0 ); + fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); + } +} + +/************************************************************************/ +/* DBFOpen() */ +/* */ +/* Open a .dbf file. */ +/************************************************************************/ + +DBFHandle SHPAPI_CALL +DBFOpen( const char * pszFilename, const char * pszAccess ) + +{ + DBFHandle psDBF; + unsigned char *pabyBuf; + int nFields, nHeadLen, nRecLen, iField, i; + char *pszBasename, *pszFullname; + +/* -------------------------------------------------------------------- */ +/* We only allow the access strings "rb" and "r+". */ +/* -------------------------------------------------------------------- */ + if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 + && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0 + && strcmp(pszAccess,"r+b") != 0 ) + return( NULL ); + + if( strcmp(pszAccess,"r") == 0 ) + pszAccess = "rb"; + + if( strcmp(pszAccess,"r+") == 0 ) + pszAccess = "rb+"; + +/* -------------------------------------------------------------------- */ +/* Compute the base (layer) name. If there is any extension */ +/* on the passed in filename we will strip it off. */ +/* -------------------------------------------------------------------- */ + pszBasename = (char *) malloc(strlen(pszFilename)+5); + strcpy( pszBasename, pszFilename ); + for( i = strlen(pszBasename)-1; + i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' + && pszBasename[i] != '\\'; + i-- ) {} + + if( pszBasename[i] == '.' ) + pszBasename[i] = '\0'; + + pszFullname = (char *) malloc(strlen(pszBasename) + 5); + sprintf( pszFullname, "%s.dbf", pszBasename ); + + psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) ); + psDBF->fp = fopen( pszFullname, pszAccess ); + + if( psDBF->fp == NULL ) + { + sprintf( pszFullname, "%s.DBF", pszBasename ); + psDBF->fp = fopen(pszFullname, pszAccess ); + } + + free( pszBasename ); + free( pszFullname ); + + if( psDBF->fp == NULL ) + { + free( psDBF ); + return( NULL ); + } + + psDBF->bNoHeader = FALSE; + psDBF->nCurrentRecord = -1; + psDBF->bCurrentRecordModified = FALSE; + +/* -------------------------------------------------------------------- */ +/* Read Table Header info */ +/* -------------------------------------------------------------------- */ + pabyBuf = (unsigned char *) malloc(500); + if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 ) + { + fclose( psDBF->fp ); + free( pabyBuf ); + free( psDBF ); + return NULL; + } + + psDBF->nRecords = + pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256; + + psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256; + psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256; + + psDBF->nFields = nFields = (nHeadLen - 32) / 32; + + psDBF->pszCurrentRecord = (char *) malloc(nRecLen); + +/* -------------------------------------------------------------------- */ +/* Read in Field Definitions */ +/* -------------------------------------------------------------------- */ + + pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen); + psDBF->pszHeader = (char *) pabyBuf; + + fseek( psDBF->fp, 32, 0 ); + if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 ) + { + fclose( psDBF->fp ); + free( pabyBuf ); + free( psDBF ); + return NULL; + } + + psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields); + psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields); + psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields); + psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields); + + for( iField = 0; iField < nFields; iField++ ) + { + unsigned char *pabyFInfo; + + pabyFInfo = pabyBuf+iField*32; + + if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' ) + { + psDBF->panFieldSize[iField] = pabyFInfo[16]; + psDBF->panFieldDecimals[iField] = pabyFInfo[17]; + } + else + { + psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256; + psDBF->panFieldDecimals[iField] = 0; + } + + psDBF->pachFieldType[iField] = (char) pabyFInfo[11]; + if( iField == 0 ) + psDBF->panFieldOffset[iField] = 1; + else + psDBF->panFieldOffset[iField] = + psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1]; + } + + return( psDBF ); +} + +/************************************************************************/ +/* DBFClose() */ +/************************************************************************/ + +void SHPAPI_CALL +DBFClose(DBFHandle psDBF) +{ +/* -------------------------------------------------------------------- */ +/* Write out header if not already written. */ +/* -------------------------------------------------------------------- */ + if( psDBF->bNoHeader ) + DBFWriteHeader( psDBF ); + + DBFFlushRecord( psDBF ); + +/* -------------------------------------------------------------------- */ +/* Update last access date, and number of records if we have */ +/* write access. */ +/* -------------------------------------------------------------------- */ + if( psDBF->bUpdated ) + { + unsigned char abyFileHeader[32]; + + fseek( psDBF->fp, 0, 0 ); + fread( abyFileHeader, 32, 1, psDBF->fp ); + + abyFileHeader[1] = 95; /* YY */ + abyFileHeader[2] = 7; /* MM */ + abyFileHeader[3] = 26; /* DD */ + + abyFileHeader[4] = psDBF->nRecords % 256; + abyFileHeader[5] = (psDBF->nRecords/256) % 256; + abyFileHeader[6] = (psDBF->nRecords/(256*256)) % 256; + abyFileHeader[7] = (psDBF->nRecords/(256*256*256)) % 256; + + fseek( psDBF->fp, 0, 0 ); + fwrite( abyFileHeader, 32, 1, psDBF->fp ); + } + +/* -------------------------------------------------------------------- */ +/* Close, and free resources. */ +/* -------------------------------------------------------------------- */ + fclose( psDBF->fp ); + + if( psDBF->panFieldOffset != NULL ) + { + free( psDBF->panFieldOffset ); + free( psDBF->panFieldSize ); + free( psDBF->panFieldDecimals ); + free( psDBF->pachFieldType ); + } + + free( psDBF->pszHeader ); + free( psDBF->pszCurrentRecord ); + + free( psDBF ); + + if( pszStringField != NULL ) + { + free( pszStringField ); + pszStringField = NULL; + nStringFieldLen = 0; + } +} + +/************************************************************************/ +/* DBFCreate() */ +/* */ +/* Create a new .dbf file. */ +/************************************************************************/ + +DBFHandle SHPAPI_CALL +DBFCreate( const char * pszFilename ) + +{ + DBFHandle psDBF; + FILE *fp; + char *pszFullname, *pszBasename; + int i; + +/* -------------------------------------------------------------------- */ +/* Compute the base (layer) name. If there is any extension */ +/* on the passed in filename we will strip it off. */ +/* -------------------------------------------------------------------- */ + pszBasename = (char *) malloc(strlen(pszFilename)+5); + strcpy( pszBasename, pszFilename ); + for( i = strlen(pszBasename)-1; + i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' + && pszBasename[i] != '\\'; + i-- ) {} + + if( pszBasename[i] == '.' ) + pszBasename[i] = '\0'; + + pszFullname = (char *) malloc(strlen(pszBasename) + 5); + sprintf( pszFullname, "%s.dbf", pszBasename ); + free( pszBasename ); + +/* -------------------------------------------------------------------- */ +/* Create the file. */ +/* -------------------------------------------------------------------- */ + fp = fopen( pszFullname, "wb" ); + if( fp == NULL ) + return( NULL ); + + fputc( 0, fp ); + fclose( fp ); + + fp = fopen( pszFullname, "rb+" ); + if( fp == NULL ) + return( NULL ); + + free( pszFullname ); + +/* -------------------------------------------------------------------- */ +/* Create the info structure. */ +/* -------------------------------------------------------------------- */ + psDBF = (DBFHandle) malloc(sizeof(DBFInfo)); + + psDBF->fp = fp; + psDBF->nRecords = 0; + psDBF->nFields = 0; + psDBF->nRecordLength = 1; + psDBF->nHeaderLength = 33; + + psDBF->panFieldOffset = NULL; + psDBF->panFieldSize = NULL; + psDBF->panFieldDecimals = NULL; + psDBF->pachFieldType = NULL; + psDBF->pszHeader = NULL; + + psDBF->nCurrentRecord = -1; + psDBF->bCurrentRecordModified = FALSE; + psDBF->pszCurrentRecord = NULL; + + psDBF->bNoHeader = TRUE; + + return( psDBF ); +} + +/************************************************************************/ +/* DBFAddField() */ +/* */ +/* Add a field to a newly created .dbf file before any records */ +/* are written. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFAddField(DBFHandle psDBF, const char * pszFieldName, + DBFFieldType eType, int nWidth, int nDecimals ) + +{ + char *pszFInfo; + int i; + +/* -------------------------------------------------------------------- */ +/* Do some checking to ensure we can add records to this file. */ +/* -------------------------------------------------------------------- */ + if( psDBF->nRecords > 0 ) + return( -1 ); + + if( !psDBF->bNoHeader ) + return( -1 ); + + if( eType != FTDouble && nDecimals != 0 ) + return( -1 ); + + if( nWidth < 1 ) + return -1; + +/* -------------------------------------------------------------------- */ +/* SfRealloc all the arrays larger to hold the additional field */ +/* information. */ +/* -------------------------------------------------------------------- */ + psDBF->nFields++; + + psDBF->panFieldOffset = (int *) + SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); + + psDBF->panFieldSize = (int *) + SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); + + psDBF->panFieldDecimals = (int *) + SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); + + psDBF->pachFieldType = (char *) + SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ); + +/* -------------------------------------------------------------------- */ +/* Assign the new field information fields. */ +/* -------------------------------------------------------------------- */ + psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength; + psDBF->nRecordLength += nWidth; + psDBF->panFieldSize[psDBF->nFields-1] = nWidth; + psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals; + + if( eType == FTLogical ) + psDBF->pachFieldType[psDBF->nFields-1] = 'L'; + else if( eType == FTString ) + psDBF->pachFieldType[psDBF->nFields-1] = 'C'; + else + psDBF->pachFieldType[psDBF->nFields-1] = 'N'; + +/* -------------------------------------------------------------------- */ +/* Extend the required header information. */ +/* -------------------------------------------------------------------- */ + psDBF->nHeaderLength += 32; + psDBF->bUpdated = FALSE; + + psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32); + + pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1); + + for( i = 0; i < 32; i++ ) + pszFInfo[i] = '\0'; + + if( (int) strlen(pszFieldName) < 10 ) + strncpy( pszFInfo, pszFieldName, strlen(pszFieldName)); + else + strncpy( pszFInfo, pszFieldName, 10); + + pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1]; + + if( eType == FTString ) + { + pszFInfo[16] = nWidth % 256; + pszFInfo[17] = nWidth / 256; + } + else + { + pszFInfo[16] = nWidth; + pszFInfo[17] = nDecimals; + } + +/* -------------------------------------------------------------------- */ +/* Make the current record buffer appropriately larger. */ +/* -------------------------------------------------------------------- */ + psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord, + psDBF->nRecordLength); + + return( psDBF->nFields-1 ); +} + +/************************************************************************/ +/* DBFReadAttribute() */ +/* */ +/* Read one of the attribute fields of a record. */ +/************************************************************************/ + +static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField, + char chReqType ) + +{ + int nRecordOffset; + unsigned char *pabyRec; + void *pReturnField = NULL; + + static double dDoubleField; + +/* -------------------------------------------------------------------- */ +/* Verify selection. */ +/* -------------------------------------------------------------------- */ + if( hEntity < 0 || hEntity >= psDBF->nRecords ) + return( NULL ); + + if( iField < 0 || iField >= psDBF->nFields ) + return( NULL ); + +/* -------------------------------------------------------------------- */ +/* Have we read the record? */ +/* -------------------------------------------------------------------- */ + if( psDBF->nCurrentRecord != hEntity ) + { + DBFFlushRecord( psDBF ); + + nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; + + if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 ) + { + fprintf( stderr, "fseek(%d) failed on DBF file.\n", + nRecordOffset ); + return NULL; + } + + if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, + 1, psDBF->fp ) != 1 ) + { + fprintf( stderr, "fread(%d) failed on DBF file.\n", + psDBF->nRecordLength ); + return NULL; + } + + psDBF->nCurrentRecord = hEntity; + } + + pabyRec = (unsigned char *) psDBF->pszCurrentRecord; + +/* -------------------------------------------------------------------- */ +/* Ensure our field buffer is large enough to hold this buffer. */ +/* -------------------------------------------------------------------- */ + if( psDBF->panFieldSize[iField]+1 > nStringFieldLen ) + { + nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10; + pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen); + } + +/* -------------------------------------------------------------------- */ +/* Extract the requested field. */ +/* -------------------------------------------------------------------- */ + strncpy( pszStringField, + ((const char *) pabyRec) + psDBF->panFieldOffset[iField], + psDBF->panFieldSize[iField] ); + pszStringField[psDBF->panFieldSize[iField]] = '\0'; + + pReturnField = pszStringField; + +/* -------------------------------------------------------------------- */ +/* Decode the field. */ +/* -------------------------------------------------------------------- */ + if( chReqType == 'N' ) + { + dDoubleField = atof(pszStringField); + + pReturnField = &dDoubleField; + } + +/* -------------------------------------------------------------------- */ +/* Should we trim white space off the string attribute value? */ +/* -------------------------------------------------------------------- */ +#ifdef TRIM_DBF_WHITESPACE + else + { + char *pchSrc, *pchDst; + + pchDst = pchSrc = pszStringField; + while( *pchSrc == ' ' ) + pchSrc++; + + while( *pchSrc != '\0' ) + *(pchDst++) = *(pchSrc++); + *pchDst = '\0'; + + while( pchDst != pszStringField && *(--pchDst) == ' ' ) + *pchDst = '\0'; + } +#endif + + return( pReturnField ); +} + +/************************************************************************/ +/* DBFReadIntAttribute() */ +/* */ +/* Read an integer attribute. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField ) + +{ + double *pdValue; + + pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' ); + + if( pdValue == NULL ) + return 0; + else + return( (int) *pdValue ); +} + +/************************************************************************/ +/* DBFReadDoubleAttribute() */ +/* */ +/* Read a double attribute. */ +/************************************************************************/ + +double SHPAPI_CALL +DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField ) + +{ + double *pdValue; + + pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' ); + + if( pdValue == NULL ) + return 0.0; + else + return( *pdValue ); +} + +/************************************************************************/ +/* DBFReadStringAttribute() */ +/* */ +/* Read a string attribute. */ +/************************************************************************/ + +const char SHPAPI_CALL1(*) +DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField ) + +{ + return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) ); +} + +/************************************************************************/ +/* DBFReadLogicalAttribute() */ +/* */ +/* Read a logical attribute. */ +/************************************************************************/ + +const char SHPAPI_CALL1(*) +DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField ) + +{ + return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) ); +} + +/************************************************************************/ +/* DBFIsAttributeNULL() */ +/* */ +/* Return TRUE if value for field is NULL. */ +/* */ +/* Contributed by Jim Matthews. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField ) + +{ + const char *pszValue; + + pszValue = DBFReadStringAttribute( psDBF, iRecord, iField ); + + switch(psDBF->pachFieldType[iField]) + { + case 'N': + case 'F': + /* NULL numeric fields have value "****************" */ + return pszValue[0] == '*'; + + case 'D': + /* NULL date fields have value "00000000" */ + return strncmp(pszValue,"00000000",8) == 0; + + case 'L': + /* NULL boolean fields have value "?" */ + return pszValue[0] == '?'; + + default: + /* empty string fields are considered NULL */ + return strlen(pszValue) == 0; + } +} + +/************************************************************************/ +/* DBFGetFieldCount() */ +/* */ +/* Return the number of fields in this table. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFGetFieldCount( DBFHandle psDBF ) + +{ + return( psDBF->nFields ); +} + +/************************************************************************/ +/* DBFGetRecordCount() */ +/* */ +/* Return the number of records in this table. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFGetRecordCount( DBFHandle psDBF ) + +{ + return( psDBF->nRecords ); +} + +/************************************************************************/ +/* DBFGetFieldInfo() */ +/* */ +/* Return any requested information about the field. */ +/************************************************************************/ + +DBFFieldType SHPAPI_CALL +DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, + int * pnWidth, int * pnDecimals ) + +{ + if( iField < 0 || iField >= psDBF->nFields ) + return( FTInvalid ); + + if( pnWidth != NULL ) + *pnWidth = psDBF->panFieldSize[iField]; + + if( pnDecimals != NULL ) + *pnDecimals = psDBF->panFieldDecimals[iField]; + + if( pszFieldName != NULL ) + { + int i; + + strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 ); + pszFieldName[11] = '\0'; + for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- ) + pszFieldName[i] = '\0'; + } + + if ( psDBF->pachFieldType[iField] == 'L' ) + return( FTLogical); + + else if( psDBF->pachFieldType[iField] == 'N' + || psDBF->pachFieldType[iField] == 'F' + || psDBF->pachFieldType[iField] == 'D' ) + { + if( psDBF->panFieldDecimals[iField] > 0 ) + return( FTDouble ); + else + return( FTInteger ); + } + else + { + return( FTString ); + } +} + +/************************************************************************/ +/* DBFWriteAttribute() */ +/* */ +/* Write an attribute record to the file. */ +/************************************************************************/ + +static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, + void * pValue ) + +{ + int nRecordOffset, i, j, nRetResult = TRUE; + unsigned char *pabyRec; + char szSField[400], szFormat[20]; + +/* -------------------------------------------------------------------- */ +/* Is this a valid record? */ +/* -------------------------------------------------------------------- */ + if( hEntity < 0 || hEntity > psDBF->nRecords ) + return( FALSE ); + + if( psDBF->bNoHeader ) + DBFWriteHeader(psDBF); + +/* -------------------------------------------------------------------- */ +/* Is this a brand new record? */ +/* -------------------------------------------------------------------- */ + if( hEntity == psDBF->nRecords ) + { + DBFFlushRecord( psDBF ); + + psDBF->nRecords++; + for( i = 0; i < psDBF->nRecordLength; i++ ) + psDBF->pszCurrentRecord[i] = ' '; + + psDBF->nCurrentRecord = hEntity; + } + +/* -------------------------------------------------------------------- */ +/* Is this an existing record, but different than the last one */ +/* we accessed? */ +/* -------------------------------------------------------------------- */ + if( psDBF->nCurrentRecord != hEntity ) + { + DBFFlushRecord( psDBF ); + + nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; + + fseek( psDBF->fp, nRecordOffset, 0 ); + fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); + + psDBF->nCurrentRecord = hEntity; + } + + pabyRec = (unsigned char *) psDBF->pszCurrentRecord; + + psDBF->bCurrentRecordModified = TRUE; + psDBF->bUpdated = TRUE; + +/* -------------------------------------------------------------------- */ +/* Translate NULL value to valid DBF file representation. */ +/* */ +/* Contributed by Jim Matthews. */ +/* -------------------------------------------------------------------- */ + if( pValue == NULL ) + { + switch(psDBF->pachFieldType[iField]) + { + case 'N': + case 'F': + /* NULL numeric fields have value "****************" */ + memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*', + psDBF->panFieldSize[iField] ); + break; + + case 'D': + /* NULL date fields have value "00000000" */ + memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0', + psDBF->panFieldSize[iField] ); + break; + + case 'L': + /* NULL boolean fields have value "?" */ + memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?', + psDBF->panFieldSize[iField] ); + break; + + default: + /* empty string fields are considered NULL */ + memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0', + psDBF->panFieldSize[iField] ); + break; + } + return TRUE; + } + +/* -------------------------------------------------------------------- */ +/* Assign all the record fields. */ +/* -------------------------------------------------------------------- */ + switch( psDBF->pachFieldType[iField] ) + { + case 'D': + case 'N': + case 'F': + if( psDBF->panFieldDecimals[iField] == 0 ) + { + int nWidth = psDBF->panFieldSize[iField]; + + if( sizeof(szSField)-2 < nWidth ) + nWidth = sizeof(szSField)-2; + + sprintf( szFormat, "%%%dd", nWidth ); + sprintf(szSField, szFormat, (int) *((double *) pValue) ); + if( (int)strlen(szSField) > psDBF->panFieldSize[iField] ) + { + szSField[psDBF->panFieldSize[iField]] = '\0'; + nRetResult = FALSE; + } + + strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), + szSField, strlen(szSField) ); + } + else + { + int nWidth = psDBF->panFieldSize[iField]; + + if( sizeof(szSField)-2 < nWidth ) + nWidth = sizeof(szSField)-2; + + sprintf( szFormat, "%%%d.%df", + nWidth, psDBF->panFieldDecimals[iField] ); + sprintf(szSField, szFormat, *((double *) pValue) ); + if( (int) strlen(szSField) > psDBF->panFieldSize[iField] ) + { + szSField[psDBF->panFieldSize[iField]] = '\0'; + nRetResult = FALSE; + } + strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), + szSField, strlen(szSField) ); + } + break; + + case 'L': + if (psDBF->panFieldSize[iField] >= 1 && + (*(char*)pValue == 'F' || *(char*)pValue == 'T')) + *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue; + break; + + default: + if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] ) + { + j = psDBF->panFieldSize[iField]; + nRetResult = FALSE; + } + else + { + memset( pabyRec+psDBF->panFieldOffset[iField], ' ', + psDBF->panFieldSize[iField] ); + j = strlen((char *) pValue); + } + + strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), + (char *) pValue, j ); + break; + } + + return( nRetResult ); +} + +/************************************************************************/ +/* DBFWriteAttributeDirectly() */ +/* */ +/* Write an attribute record to the file, but without any */ +/* reformatting based on type. The provided buffer is written */ +/* as is to the field position in the record. */ +/************************************************************************/ + +int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, + void * pValue ) + +{ + int nRecordOffset, i, j; + unsigned char *pabyRec; + +/* -------------------------------------------------------------------- */ +/* Is this a valid record? */ +/* -------------------------------------------------------------------- */ + if( hEntity < 0 || hEntity > psDBF->nRecords ) + return( FALSE ); + + if( psDBF->bNoHeader ) + DBFWriteHeader(psDBF); + +/* -------------------------------------------------------------------- */ +/* Is this a brand new record? */ +/* -------------------------------------------------------------------- */ + if( hEntity == psDBF->nRecords ) + { + DBFFlushRecord( psDBF ); + + psDBF->nRecords++; + for( i = 0; i < psDBF->nRecordLength; i++ ) + psDBF->pszCurrentRecord[i] = ' '; + + psDBF->nCurrentRecord = hEntity; + } + +/* -------------------------------------------------------------------- */ +/* Is this an existing record, but different than the last one */ +/* we accessed? */ +/* -------------------------------------------------------------------- */ + if( psDBF->nCurrentRecord != hEntity ) + { + DBFFlushRecord( psDBF ); + + nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; + + fseek( psDBF->fp, nRecordOffset, 0 ); + fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); + + psDBF->nCurrentRecord = hEntity; + } + + pabyRec = (unsigned char *) psDBF->pszCurrentRecord; + +/* -------------------------------------------------------------------- */ +/* Assign all the record fields. */ +/* -------------------------------------------------------------------- */ + if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] ) + j = psDBF->panFieldSize[iField]; + else + { + memset( pabyRec+psDBF->panFieldOffset[iField], ' ', + psDBF->panFieldSize[iField] ); + j = strlen((char *) pValue); + } + + strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), + (char *) pValue, j ); + + psDBF->bCurrentRecordModified = TRUE; + psDBF->bUpdated = TRUE; + + return( TRUE ); +} + +/************************************************************************/ +/* DBFWriteDoubleAttribute() */ +/* */ +/* Write a double attribute. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField, + double dValue ) + +{ + return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); +} + +/************************************************************************/ +/* DBFWriteIntegerAttribute() */ +/* */ +/* Write a integer attribute. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField, + int nValue ) + +{ + double dValue = nValue; + + return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); +} + +/************************************************************************/ +/* DBFWriteStringAttribute() */ +/* */ +/* Write a string attribute. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField, + const char * pszValue ) + +{ + return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) ); +} + +/************************************************************************/ +/* DBFWriteNULLAttribute() */ +/* */ +/* Write a string attribute. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField ) + +{ + return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) ); +} + +/************************************************************************/ +/* DBFWriteLogicalAttribute() */ +/* */ +/* Write a logical attribute. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField, + const char lValue) + +{ + return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) ); +} + +/************************************************************************/ +/* DBFWriteTuple() */ +/* */ +/* Write an attribute record to the file. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple ) + +{ + int nRecordOffset, i; + unsigned char *pabyRec; + +/* -------------------------------------------------------------------- */ +/* Is this a valid record? */ +/* -------------------------------------------------------------------- */ + if( hEntity < 0 || hEntity > psDBF->nRecords ) + return( FALSE ); + + if( psDBF->bNoHeader ) + DBFWriteHeader(psDBF); + +/* -------------------------------------------------------------------- */ +/* Is this a brand new record? */ +/* -------------------------------------------------------------------- */ + if( hEntity == psDBF->nRecords ) + { + DBFFlushRecord( psDBF ); + + psDBF->nRecords++; + for( i = 0; i < psDBF->nRecordLength; i++ ) + psDBF->pszCurrentRecord[i] = ' '; + + psDBF->nCurrentRecord = hEntity; + } + +/* -------------------------------------------------------------------- */ +/* Is this an existing record, but different than the last one */ +/* we accessed? */ +/* -------------------------------------------------------------------- */ + if( psDBF->nCurrentRecord != hEntity ) + { + DBFFlushRecord( psDBF ); + + nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; + + fseek( psDBF->fp, nRecordOffset, 0 ); + fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); + + psDBF->nCurrentRecord = hEntity; + } + + pabyRec = (unsigned char *) psDBF->pszCurrentRecord; + + memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength ); + + psDBF->bCurrentRecordModified = TRUE; + psDBF->bUpdated = TRUE; + + return( TRUE ); +} + +/************************************************************************/ +/* DBFReadTuple() */ +/* */ +/* Read one of the attribute fields of a record. */ +/************************************************************************/ + +const char SHPAPI_CALL1(*) +DBFReadTuple(DBFHandle psDBF, int hEntity ) + +{ + int nRecordOffset; + unsigned char *pabyRec; + static char *pReturnTuple = NULL; + + static int nTupleLen = 0; + +/* -------------------------------------------------------------------- */ +/* Have we read the record? */ +/* -------------------------------------------------------------------- */ + if( hEntity < 0 || hEntity >= psDBF->nRecords ) + return( NULL ); + + if( psDBF->nCurrentRecord != hEntity ) + { + DBFFlushRecord( psDBF ); + + nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; + + fseek( psDBF->fp, nRecordOffset, 0 ); + fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); + + psDBF->nCurrentRecord = hEntity; + } + + pabyRec = (unsigned char *) psDBF->pszCurrentRecord; + + if ( nTupleLen < psDBF->nRecordLength) { + nTupleLen = psDBF->nRecordLength; + pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength); + } + + memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength ); + + return( pReturnTuple ); +} + +/************************************************************************/ +/* DBFCloneEmpty() */ +/* */ +/* Read one of the attribute fields of a record. */ +/************************************************************************/ + +DBFHandle SHPAPI_CALL +DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) +{ + DBFHandle newDBF; + + newDBF = DBFCreate ( pszFilename ); + if ( newDBF == NULL ) return ( NULL ); + + newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields ); + memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields ); + + newDBF->nFields = psDBF->nFields; + newDBF->nRecordLength = psDBF->nRecordLength; + newDBF->nHeaderLength = 32 * (psDBF->nFields+1); + + newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); + memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); + newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields ); + memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); + newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields ); + memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); + newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields ); + memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields ); + + newDBF->bNoHeader = TRUE; + newDBF->bUpdated = TRUE; + + DBFWriteHeader ( newDBF ); + DBFClose ( newDBF ); + + newDBF = DBFOpen ( pszFilename, "rb+" ); + + return ( newDBF ); +} + +/************************************************************************/ +/* DBFGetNativeFieldType() */ +/* */ +/* Return the DBase field type for the specified field. */ +/* */ +/* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */ +/* 'N' (Numeric, with or without decimal), */ +/* 'L' (Logical), */ +/* 'M' (Memo: 10 digits .DBT block ptr) */ +/************************************************************************/ + +char SHPAPI_CALL +DBFGetNativeFieldType( DBFHandle psDBF, int iField ) + +{ + if( iField >=0 && iField < psDBF->nFields ) + return psDBF->pachFieldType[iField]; + + return ' '; +} + +/************************************************************************/ +/* str_to_upper() */ +/************************************************************************/ + +static void str_to_upper (char *string) +{ + int len; + short i = -1; + + len = strlen (string); + + while (++i < len) + if (isalpha(string[i]) && islower(string[i])) + string[i] = toupper ((int)string[i]); +} + +/************************************************************************/ +/* DBFGetFieldIndex() */ +/* */ +/* Get the index number for a field in a .dbf file. */ +/* */ +/* Contributed by Jim Matthews. */ +/************************************************************************/ + +int SHPAPI_CALL +DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName) + +{ + char name[12], name1[12], name2[12]; + int i; + + strncpy(name1, pszFieldName,11); + name1[11] = '\0'; + str_to_upper(name1); + + for( i = 0; i < DBFGetFieldCount(psDBF); i++ ) + { + DBFGetFieldInfo( psDBF, i, name, NULL, NULL ); + strncpy(name2,name,11); + str_to_upper(name2); + + if(!strncmp(name1,name2,10)) + return(i); + } + return(-1); +} diff --git a/shapelib/shapefil.h b/shapelib/shapefil.h new file mode 100644 index 000000000..00d7d0d2b --- /dev/null +++ b/shapelib/shapefil.h @@ -0,0 +1,490 @@ +#ifndef _SHAPEFILE_H_INCLUDED +#define _SHAPEFILE_H_INCLUDED + +/****************************************************************************** + * $Id: shapefil.h,v 1.2 2004/09/27 01:13:58 robertl Exp $ + * + * Project: Shapelib + * Purpose: Primary include file for Shapelib. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 1999, Frank Warmerdam + * + * This software is available under the following "MIT Style" license, + * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This + * option is discussed in more detail in shapelib.html. + * + * -- + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************** + * + * $Log: shapefil.h,v $ + * Revision 1.2 2004/09/27 01:13:58 robertl + * warning fixes in shapelib. From Alexander Stohr. + * + * Revision 1.1 2004/09/20 17:22:55 robertl + * Bring in shapefil.h. + * + * Revision 1.26 2002/09/29 00:00:08 warmerda + * added FTLogical and logical attribute read/write calls + * + * Revision 1.25 2002/05/07 13:46:30 warmerda + * added DBFWriteAttributeDirectly(). + * + * Revision 1.24 2002/04/10 16:59:54 warmerda + * added SHPRewindObject + * + * Revision 1.23 2002/01/15 14:36:07 warmerda + * updated email address + * + * Revision 1.22 2002/01/15 14:32:00 warmerda + * try to improve SHPAPI_CALL docs + * + * Revision 1.21 2001/11/01 16:29:55 warmerda + * move pabyRec into SHPInfo for thread safety + * + * Revision 1.20 2001/07/20 13:06:02 warmerda + * fixed SHPAPI attribute for SHPTreeFindLikelyShapes + * + * Revision 1.19 2001/05/31 19:20:13 warmerda + * added DBFGetFieldIndex() + * + * Revision 1.18 2001/05/31 18:15:40 warmerda + * Added support for NULL fields in DBF files + * + * Revision 1.17 2001/05/23 13:36:52 warmerda + * added use of SHPAPI_CALL + * + * Revision 1.16 2000/09/25 14:15:59 warmerda + * added DBFGetNativeFieldType() + * + * Revision 1.15 2000/02/16 16:03:51 warmerda + * added null shape support + * + * Revision 1.14 1999/11/05 14:12:05 warmerda + * updated license terms + * + * Revision 1.13 1999/06/02 18:24:21 warmerda + * added trimming code + * + * Revision 1.12 1999/06/02 17:56:12 warmerda + * added quad'' subnode support for trees + * + * Revision 1.11 1999/05/18 19:11:11 warmerda + * Added example searching capability + * + * Revision 1.10 1999/05/18 17:49:38 warmerda + * added initial quadtree support + * + * Revision 1.9 1999/05/11 03:19:28 warmerda + * added new Tuple api, and improved extension handling - add from candrsn + * + * Revision 1.8 1999/03/23 17:22:27 warmerda + * Added extern "C" protection for C++ users of shapefil.h. + * + * Revision 1.7 1998/12/31 15:31:07 warmerda + * Added the TRIM_DBF_WHITESPACE and DISABLE_MULTIPATCH_MEASURE options. + * + * Revision 1.6 1998/12/03 15:48:15 warmerda + * Added SHPCalculateExtents(). + * + * Revision 1.5 1998/11/09 20:57:16 warmerda + * Altered SHPGetInfo() call. + * + * Revision 1.4 1998/11/09 20:19:33 warmerda + * Added 3D support, and use of SHPObject. + * + * Revision 1.3 1995/08/23 02:24:05 warmerda + * Added support for reading bounds. + * + * Revision 1.2 1995/08/04 03:17:39 warmerda + * Added header. + * + */ + +#include + +#ifdef USE_DBMALLOC +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************/ +/* Configuration options. */ +/************************************************************************/ + +/* -------------------------------------------------------------------- */ +/* Should the DBFReadStringAttribute() strip leading and */ +/* trailing white space? */ +/* -------------------------------------------------------------------- */ +#define TRIM_DBF_WHITESPACE + +/* -------------------------------------------------------------------- */ +/* Should we write measure values to the Multipatch object? */ +/* Reportedly ArcView crashes if we do write it, so for now it */ +/* is disabled. */ +/* -------------------------------------------------------------------- */ +#define DISABLE_MULTIPATCH_MEASURE + +/* -------------------------------------------------------------------- */ +/* SHPAPI_CALL */ +/* */ +/* The following two macros are present to allow forcing */ +/* various calling conventions on the Shapelib API. */ +/* */ +/* To force __stdcall conventions (needed to call Shapelib */ +/* from Visual Basic and/or Dephi I believe) the makefile could */ +/* be modified to define: */ +/* */ +/* /DSHPAPI_CALL=__stdcall */ +/* */ +/* If it is desired to force export of the Shapelib API without */ +/* using the shapelib.def file, use the following definition. */ +/* */ +/* /DSHAPELIB_DLLEXPORT */ +/* */ +/* To get both at once it will be necessary to hack this */ +/* include file to define: */ +/* */ +/* #define SHPAPI_CALL __declspec(dllexport) __stdcall */ +/* #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall */ +/* */ +/* The complexity of the situtation is partly caused by the */ +/* peculiar requirement of Visual C++ that __stdcall appear */ +/* after any "*"'s in the return value of a function while the */ +/* __declspec(dllexport) must appear before them. */ +/* -------------------------------------------------------------------- */ + +#ifdef SHAPELIB_DLLEXPORT +# define SHPAPI_CALL __declspec(dllexport) +# define SHPAPI_CALL1(x) __declspec(dllexport) x +#endif + +#ifndef SHPAPI_CALL +# define SHPAPI_CALL +#endif + +#ifndef SHPAPI_CALL1 +# define SHPAPI_CALL1(x) x SHPAPI_CALL +#endif + +/************************************************************************/ +/* SHP Support. */ +/************************************************************************/ +typedef struct +{ + FILE *fpSHP; + FILE *fpSHX; + + int nShapeType; /* SHPT_* */ + + int nFileSize; /* SHP file */ + + int nRecords; + int nMaxRecords; + int *panRecOffset; + int *panRecSize; + + double adBoundsMin[4]; + double adBoundsMax[4]; + + int bUpdated; + + unsigned char *pabyRec; + int nBufSize; +} SHPInfo; + +typedef SHPInfo * SHPHandle; + +/* -------------------------------------------------------------------- */ +/* Shape types (nSHPType) */ +/* -------------------------------------------------------------------- */ +#define SHPT_NULL 0 +#define SHPT_POINT 1 +#define SHPT_ARC 3 +#define SHPT_POLYGON 5 +#define SHPT_MULTIPOINT 8 +#define SHPT_POINTZ 11 +#define SHPT_ARCZ 13 +#define SHPT_POLYGONZ 15 +#define SHPT_MULTIPOINTZ 18 +#define SHPT_POINTM 21 +#define SHPT_ARCM 23 +#define SHPT_POLYGONM 25 +#define SHPT_MULTIPOINTM 28 +#define SHPT_MULTIPATCH 31 + + +/* -------------------------------------------------------------------- */ +/* Part types - everything but SHPT_MULTIPATCH just uses */ +/* SHPP_RING. */ +/* -------------------------------------------------------------------- */ + +#define SHPP_TRISTRIP 0 +#define SHPP_TRIFAN 1 +#define SHPP_OUTERRING 2 +#define SHPP_INNERRING 3 +#define SHPP_FIRSTRING 4 +#define SHPP_RING 5 + +/* -------------------------------------------------------------------- */ +/* SHPObject - represents on shape (without attributes) read */ +/* from the .shp file. */ +/* -------------------------------------------------------------------- */ +typedef struct +{ + int nSHPType; + + int nShapeId; /* -1 is unknown/unassigned */ + + int nParts; + int *panPartStart; + int *panPartType; + + int nVertices; + double *padfX; + double *padfY; + double *padfZ; + double *padfM; + + double dfXMin; + double dfYMin; + double dfZMin; + double dfMMin; + + double dfXMax; + double dfYMax; + double dfZMax; + double dfMMax; +} SHPObject; + +/* -------------------------------------------------------------------- */ +/* SHP API Prototypes */ +/* -------------------------------------------------------------------- */ +SHPHandle SHPAPI_CALL + SHPOpen( const char * pszShapeFile, const char * pszAccess ); +SHPHandle SHPAPI_CALL + SHPCreate( const char * pszShapeFile, int nShapeType ); +void SHPAPI_CALL + SHPGetInfo( SHPHandle hSHP, int * pnEntities, int * pnShapeType, + double * padfMinBound, double * padfMaxBound ); + +SHPObject SHPAPI_CALL1(*) + SHPReadObject( SHPHandle hSHP, int iShape ); +int SHPAPI_CALL + SHPWriteObject( SHPHandle hSHP, int iShape, SHPObject * psObject ); + +void SHPAPI_CALL + SHPDestroyObject( SHPObject * psObject ); +void SHPAPI_CALL + SHPComputeExtents( SHPObject * psObject ); +SHPObject SHPAPI_CALL1(*) + SHPCreateObject( int nSHPType, int nShapeId, + int nParts, int * panPartStart, int * panPartType, + int nVertices, const double * padfX, const double * padfY, + const double * padfZ, const double * padfM ); +SHPObject SHPAPI_CALL1(*) + SHPCreateSimpleObject( int nSHPType, int nVertices, + const double * padfX, const double * padfY, const double * padfZ ); + +int SHPAPI_CALL + SHPRewindObject( SHPHandle hSHP, SHPObject * psObject ); + +void SHPAPI_CALL + SHPClose( SHPHandle hSHP ); + +const char SHPAPI_CALL1(*) + SHPTypeName( int nSHPType ); +const char SHPAPI_CALL1(*) + SHPPartTypeName( int nPartType ); + +/* -------------------------------------------------------------------- */ +/* Shape quadtree indexing API. */ +/* -------------------------------------------------------------------- */ + +/* this can be two or four for binary or quad tree */ +#define MAX_SUBNODE 4 + +typedef struct shape_tree_node +{ + /* region covered by this node */ + double adfBoundsMin[4]; + double adfBoundsMax[4]; + + /* list of shapes stored at this node. The papsShapeObj pointers + or the whole list can be NULL */ + int nShapeCount; + int *panShapeIds; + SHPObject **papsShapeObj; + + int nSubNodes; + struct shape_tree_node *apsSubNode[MAX_SUBNODE]; + +} SHPTreeNode; + +typedef struct +{ + SHPHandle hSHP; + + int nMaxDepth; + int nDimension; + + SHPTreeNode *psRoot; +} SHPTree; + +SHPTree SHPAPI_CALL1(*) + SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth, + double *padfBoundsMin, double *padfBoundsMax ); +void SHPAPI_CALL + SHPDestroyTree( SHPTree * hTree ); + +int SHPAPI_CALL + SHPWriteTree( SHPTree *hTree, const char * pszFilename ); +SHPTree SHPAPI_CALL + SHPReadTree( const char * pszFilename ); + +int SHPAPI_CALL + SHPTreeAddObject( SHPTree * hTree, SHPObject * psObject ); +int SHPAPI_CALL + SHPTreeAddShapeId( SHPTree * hTree, SHPObject * psObject ); +int SHPAPI_CALL + SHPTreeRemoveShapeId( SHPTree * hTree, int nShapeId ); + +void SHPAPI_CALL + SHPTreeTrimExtraNodes( SHPTree * hTree ); + +int SHPAPI_CALL1(*) + SHPTreeFindLikelyShapes( SHPTree * hTree, + double * padfBoundsMin, + double * padfBoundsMax, + int * ); +int SHPAPI_CALL + SHPCheckBoundsOverlap( double *, double *, double *, double *, int ); + +/************************************************************************/ +/* DBF Support. */ +/************************************************************************/ +typedef struct +{ + FILE *fp; + + int nRecords; + + int nRecordLength; + int nHeaderLength; + int nFields; + int *panFieldOffset; + int *panFieldSize; + int *panFieldDecimals; + char *pachFieldType; + + char *pszHeader; + + int nCurrentRecord; + int bCurrentRecordModified; + char *pszCurrentRecord; + + int bNoHeader; + int bUpdated; +} DBFInfo; + +typedef DBFInfo * DBFHandle; + +typedef enum { + FTString, + FTInteger, + FTDouble, + FTLogical, + FTInvalid +} DBFFieldType; + +#define XBASE_FLDHDR_SZ 32 + +DBFHandle SHPAPI_CALL + DBFOpen( const char * pszDBFFile, const char * pszAccess ); +DBFHandle SHPAPI_CALL + DBFCreate( const char * pszDBFFile ); + +int SHPAPI_CALL + DBFGetFieldCount( DBFHandle psDBF ); +int SHPAPI_CALL + DBFGetRecordCount( DBFHandle psDBF ); +int SHPAPI_CALL + DBFAddField( DBFHandle hDBF, const char * pszFieldName, + DBFFieldType eType, int nWidth, int nDecimals ); + +DBFFieldType SHPAPI_CALL + DBFGetFieldInfo( DBFHandle psDBF, int iField, + char * pszFieldName, int * pnWidth, int * pnDecimals ); + +int SHPAPI_CALL + DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName); + +int SHPAPI_CALL + DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField ); +double SHPAPI_CALL + DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField ); +const char SHPAPI_CALL1(*) + DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField ); +const char SHPAPI_CALL1(*) + DBFReadLogicalAttribute( DBFHandle hDBF, int iShape, int iField ); +int SHPAPI_CALL + DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField ); + +int SHPAPI_CALL + DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField, + int nFieldValue ); +int SHPAPI_CALL + DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField, + double dFieldValue ); +int SHPAPI_CALL + DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField, + const char * pszFieldValue ); +int SHPAPI_CALL + DBFWriteNULLAttribute( DBFHandle hDBF, int iShape, int iField ); + +int SHPAPI_CALL + DBFWriteLogicalAttribute( DBFHandle hDBF, int iShape, int iField, + const char lFieldValue); +int SHPAPI_CALL + DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, + void * pValue ); +const char SHPAPI_CALL1(*) + DBFReadTuple(DBFHandle psDBF, int hEntity ); +int SHPAPI_CALL + DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple ); + +DBFHandle SHPAPI_CALL + DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ); + +void SHPAPI_CALL + DBFClose( DBFHandle hDBF ); +char SHPAPI_CALL + DBFGetNativeFieldType( DBFHandle hDBF, int iField ); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef _SHAPEFILE_H_INCLUDED */ diff --git a/shapelib/shapelib.html b/shapelib/shapelib.html new file mode 100644 index 000000000..4372d1d6c --- /dev/null +++ b/shapelib/shapelib.html @@ -0,0 +1,334 @@ + + +Shapefile C Library V1.2 + + + +

Shapefile C Library V1.2

+ +

Purpose

+ +The Shapefile C Library provides the ability to write simple C programs +for reading, writing and updating (to a limited extent) ESRI Shapefiles, +and the associated attribute file (.dbf).

+ +

Manifest

+ +
+ +

What is a Shapefile?

+ +If you don't know, you probably don't need this library. The Shapefile +format is a new working and interchange format promulagated by ESRI +(http://www.esri.com/) for simple vector data with attributes. It is +apparently the only file format that can be edited in ARCView 2/3, and can +also be exported and imported in Arc/Info.

+ +An excellent white paper on the shapefile format is available from ESRI, +but it is .pdf format, so you will need Adobe Acrobat to browse it.

+ +The file format actually consists of three files.

+ +

+XXX.shp - holds the actual vertices.
+XXX.shx - hold index data pointing to the structures in the .shp file.
+XXX.dbf - holds the attributes in xBase (dBase) format.  
+
+ +

Release Notes

+ +To get notification of new releases of Shapelib subscribe to +the project at www.freshmeat.net. This is currently the only reliable +way of finding out about new releases since there is no shapelib specific +mailing list.

+ +Release 1.2.10: Added SHPRewindObject() function, and shprewind utility +program. Added FTLogical, DBFReadLogicalAttribute() and +DBFWriteLogicalAttribute() (thanks to Olek Neyman).

+ +Release 1.2.9: Good support for reading and writing NULL fields +in .dbf files, good support for NULL shapes and addition of the +DBFGetFieldIndex() functions (all contributed by Jim Matthews).

+ +An upgraded shputils.c has been contributed by Bill Miller. Daniel +Morissette contributed DBFGetNativeFieldType(). Better error checking +for disk errors in dbfopen.c. Various other bug fixes and safety improvements. +

+ +Release 1.2.8: Added hacked libtool support (supplied by Jan) +and "rpm ready" install logic.

+ +Release 1.2.7: Fix record size (was 4 bytes too long). Modify +SHPReadObject() to handle null shapes properly. Use atof() instead of +sscanf(). Support .DBF as well as .dbf.

+ +Release 1.2.6: Now available under old MIT style license, or at the +users option, LGPL. Added the contrib directory of stuff from Carl Anderson +and the shptree.c API for quadtree based spatial searches.

+ +Release 1.2.5: SHPOpen() now forcably uses "rb" or "r+b" access string +to avoid common mistakes on Windows. Also fixed a serious bug with .dbf +files with a 'F' field type.

+ +Release 1.2.4: DBFOpen() will now automatically translate a .shp +extension to .dbf for convenience. SHPOpen() will try datasets with lower +and uppercase extension. DBFAddField() now returns the field number, +not TRUE/FALSE.

+ +Release 1.2.3: Disable writing measures to multi-patches as ArcView +seems to puke on them (as reported by Monika Sester). Add white space +trimming, and string/numeric attribute interchangability in DBF API +as suggested by Steve Lime. Dbfdump was updated to include several +reporting options.

+ +Release 1.2.2: Added proper support for multipatch (reading and +writing) - this release just for testing purposes.

+ +Release 1.2 is mostly a rewrite of the .shp/.shx access API to account +for ArcView 3.x 3D shapes, and to encapsulate the shapes in a structure. +Existing code using the shapefile library will require substantial changes +to use release 1.2.

+ +Release V1.1 has been built on a number of platforms, and used by a +number of people successfully. V1.1 is the first release with the xBase API +documentation.

+ + +

Maintainer

+ +This library is maintained by me (Frank Warmerdam) on my own time. Please +send me bug patches and suggestions for the library. Email can be sent to +warmerdam@pobox.com.

+ +The current status of the Shapelib code can be found at + +http://pobox.com/~warmerdam/root/projects/shapelib/. To find out about +new releases of Shapelib, select the "Subscribe to new releases" option +from the link at +Freshmeat.

+ +The shputils.c module was contributed by Bill Miller (NC-DOT) who can be +reached at bmiller@doh.dot.state.nc.us. I had to modify it substantially +to work with the 1.2 API, and I am not sure that it works as well as it +did when it was originally provided by Bill.

+ +

Credits

+ +I didn't start this section anywhere near soon enough, so alot of earlier +contributors to Shapelib are lost in pre-history. + +
    +
  • Bill Miller (NY-DOT) for shputils.c +
  • Carl Anderson for the contents of the contrib directory, and +the "tuple" additions to dbfopen.c. +
  • Andrea Giacomelli for patches for dbfopen.c. +
  • Doug Matthews for portability improvements. +
  • Jan-Oliver Wagner for convincing me to make it available under LGPL, +shared library support, and various other patches. +
  • Dennis Christopher (of Avenza) for testing and bug fixes. +
  • Miko Syrjä (of 3D-system Oy) for a record size bug fix. +
  • Steven Lime and Curtis Hill for help with NULL shapes. +
  • Jim Matthews for support of NULL attributes in dbf files. +
  • PCI Geomatics who let me +release a modified version of their shapefile code in the beginning and +who hosted shapelib for years. +
+ +

In Memorium

+ +I would like to dedicate Shapelib to the memory of Sol Katz. While I never +met him in person, his generous contributions to the GIS community took +many forms, including free distribution of a variety of GIS translators +with source. The fact that he used this Shapelib in some of his utilities, +and thanked me was a great encouragement to me. I hope I can do his memory +honour by trying to contribute in a similar fashion.

+ +

Portability

+ +The Shapefile C Library should port easily to 32bit systems with ANSI C +compilers. It should work on 64 bit architectures (such as the DEC AXP).

+ +Care should also be taken to pass the binary access flag into SHPOpen() +and DBFOpen() when operating on systems with special text file translation +such as MSDOS.

+ +The shputils.c module is contributed, and may not take the same approach +to portability as the rest of the package.

+ +On Linux, and most unix systems it should be possible to build and +install shapefile support as a shared library using the "lib" and "lib_install" +targets of the Makefile. Note that this Makefile doesn't use autoconf +mechanisms and will generally require some hand tailoring for your environment. + +

Limitations

+ +
    + +
  • You can't modify the vertices of existing structures (though you + can update the attributes of existing structures, and create new + structures).

    + +

  • Not written in such a way as to be particularly fast. This is +particularly true of the 1.2 API. For applications more concerned with +speed it may be worth using the V1.1 API.

    + +

  • Doesn't set the last access time properly in the .dbf files.

    + +

  • There is no way to synchronize information to the file except to close it. +

    + +

  • Poor error checking and reporting.

    + +

  • Not professionally supported (well it can be, if you want to pay).

    + +

  • Some aspects of xBase files not supported, though I believe they are +not used by ESRI.

    + +

  • The application must keep the .dbf file in sync with the .shp/.shx +files through appropriate use of the DBF and SHP APIs.

    + +

  • No support for the undocumented .sbn/.sbx spatial index files.

    + +

+ +

Copyright

+ +The source for the Shapefile C Library is (c) 1998 Frank Warmerdam, +and released under the following conditions. The intent is that anyone +can do anything with the code, but that I do not assume any liability, nor +express any warranty for this code.

+ +As of Shapelib 1.2.6 the core portions of the library are made available +under two possible licenses. The licensee can choose to use the code +under either the Library GNU Public License (LGPL) described in +LICENSE.LGPL or under the following MIT style license. Any files in +the Shapelib distribution without explicit copyright license terms +(such as this documentation, the Makefile and so forth) should be +considered to have the following licensing terms. Some auxilary portions +of Shapelib, notably some of the components in the contrib directory +come under slightly different license restrictions. Check the source +files that you are actually using for conditions.

+ +

Default License Terms

+ + +Copyright (c) 1999, Frank Warmerdam

+ +This software is available under the following "MIT Style" license, +or at the option of the licensee under the LGPL (see LICENSE.LGPL). This +option is discussed in more detail in shapelib.html.

+ +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions:

+ +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software.

+ +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE.

+ + +

Shapelib Modifications

+ +I am pleased to receive bug fixes, and improvements for Shapelib. Unless +the submissions indicate otherwise I will assume that changes submitted to +me remain under the the above "dual license" terms. If changes are made +to the library with the intention that those changes should be protected by +the LGPL then I should be informed upon submission. Note that I will not +generally incorporate changes into the core of Shapelib that are protected +under the LGPL as this would effectively limit the whole file and +distribution to LGPL terms.

+ +

Opting for LGPL

+ +For licensee's opting to use Shapelib under LGPL as opposed to the MIT +Style license above, and wishing to redistribute the software based on +Shapelib, I would ask that all "dual license" modules be updated to +indicate that only the LGPL (and not the MIT Style license) applies. This +action represents opting for the LGPL, and thereafter LGPL terms apply to +any redistribution and modification of the affected modules.

+ + + + + + diff --git a/shapelib/shp_api.html b/shapelib/shp_api.html new file mode 100644 index 000000000..d773e3e56 --- /dev/null +++ b/shapelib/shp_api.html @@ -0,0 +1,376 @@ + + +.SHP File API + + + +

.SHP File API

+ +The .SHP API uses a SHPHandle to represent an open .shp/.shx file pair. +The contents of the SHPHandle are visible (see shapefile.h) but should +be ignored by the application. It is intended that all information be +accessed by the API functions.

+ + + +

Shape Types

+ +Shapes have types associated with them. The following is a list of the +different shapetypes supported by Shapefiles. At this time all shapes in +a Shapefile must be of the same type (with the exception of NULL shapes).

+ +

+  #define SHPT_NULL             0
+
+  2D Shape Types (pre ArcView 3.x):
+
+  #define SHPT_POINT		1	Points
+  #define SHPT_ARC		3	Arcs (Polylines, possible in parts)
+  #define SHPT_POLYGON		5	Polygons (possible in parts)
+  #define SHPT_MULTIPOINT	8	MultiPoint (related points)
+
+  3D Shape Types (may include "measure" values for vertices):
+
+  #define SHPT_POINTZ		11	
+  #define SHPT_ARCZ		13
+  #define SHPT_POLYGONZ		15
+  #define SHPT_MULTIPOINTZ 	18
+
+  2D + Measure Types:
+
+  #define SHPT_POINTM		21
+  #define SHPT_ARCM		23
+  #define SHPT_POLYGONM		25
+  #define SHPT_MULTIPOINTM 	28
+
+  Complex (TIN-like) with Z, and Measure:
+
+  #define SHPT_MULTIPATCH 	31
+
+ + + +

SHPObject

+ +An individual shape is represented by the SHPObject structure. SHPObject's +created with SHPCreateObject(), SHPCreateSimpleObject(), or SHPReadObject() +should be disposed of with SHPDestroyObject().

+ +

+  typedef struct
+  {
+    int		nSHPType;	Shape Type (SHPT_* - see list above)
+
+    int		nShapeId; 	Shape Number (-1 is unknown/unassigned)
+
+    int		nParts;		# of Parts (0 implies single part with no info)
+    int		*panPartStart;  Start Vertex of part
+    int		*panPartType;	Part Type (SHPP_RING if not SHPT_MULTIPATCH)
+    
+    int		nVertices;	Vertex list 
+    double	*padfX;		
+    double	*padfY;
+    double	*padfZ;		(all zero if not provided)
+    double	*padfM;		(all zero if not provided)
+
+    double	dfXMin;		Bounds in X, Y, Z and M dimensions
+    double	dfYMin;
+    double	dfZMin;
+    double	dfMMin;
+
+    double	dfXMax;
+    double	dfYMax;
+    double	dfZMax;
+    double	dfMMax;
+  } SHPObject;
+
+ + + +

SHPOpen()

+ +
+SHPHandle SHPOpen( const char * pszShapeFile, const char * pszAccess );
+
+  pszShapeFile:		The name of the layer to access.  This can be the
+			name of either the .shp or the .shx file or can
+			just be the path plus the basename of the pair.
+
+  pszAccess:		The fopen() style access string.  At this time only
+			"rb" (read-only binary) and "rb+" (read/write binary) 
+		        should be used.
+
+ + The SHPOpen() function should be used to establish access to the two files + for accessing vertices (.shp and .shx). Note that both files have to + be in the indicated directory, and must have the expected extensions in + lower case. The returned SHPHandle is passed to other access functions, + and SHPClose() should be invoked to recover resources, and flush changes + to disk when complete.

+ + + +

SHPGetInfo()

+ +
+void SHPGetInfo( SHPHandle hSHP, int * pnEntities, int * pnShapeType,
+                 double * padfMinBound, double * padfMaxBound );
+
+  hSHP:			The handle previously returned by SHPOpen() 
+			or SHPCreate().
+
+  pnEntities:		A pointer to an integer into which the number of
+			entities/structures should be placed.  May be NULL.
+
+  pnShapetype:		A pointer to an integer into which the shapetype
+			of this file should be placed.  Shapefiles may contain
+			either SHPT_POINT, SHPT_ARC, SHPT_POLYGON or 
+			SHPT_MULTIPOINT entities.  This may be NULL.
+
+  padfMinBound:		The X, Y, Z and M minimum values will be placed into
+                        this four entry array.  This may be NULL.
+			
+  padfMaxBound:		The X, Y, Z and M maximum values will be placed into
+                        this four entry array.  This may be NULL.
+
+ + The SHPGetInfo() function retrieves various information about shapefile + as a whole. The bounds are read from the file header, and may be + inaccurate if the file was improperly generated.

+ + + +

SHPReadObject()

+ +
+SHPObject *SHPReadObject( SHPHandle hSHP, int iShape );
+
+  hSHP:			The handle previously returned by SHPOpen() 
+			or SHPCreate().
+
+  iShape:		The entity number of the shape to read.  Entity 
+			numbers are between 0 and nEntities-1 (as returned
+			by SHPGetInfo()).
+
+ + The SHPReadObject() call is used to read a single structure, or entity + from the shapefile. See the definition of the SHPObject structure for + detailed information on fields of a SHPObject. SHPObject's returned from + SHPReadObject() should be deallocated with SHPDestroyShape(). + SHPReadObject() will return NULL if an illegal iShape value is requested.

+ + Note that the bounds placed into the SHPObject are those read from the + file, and may not be correct. For points the bounds are generated from + the single point since bounds aren't normally provided for point types.

+ + Generally the shapes returned will be of the type of the file as a whole. + However, any file may also contain type SHPT_NULL shapes which will have + no geometry. Generally speaking applications should skip rather than + preserve them, as they usually represented interactively deleted shapes.

+ + + +

SHPClose()

+ +
+void	SHPClose( SHPHandle hSHP );
+
+  hSHP:			The handle previously returned by SHPOpen() 
+			or SHPCreate().
+
+ + The SHPClose() function will close the .shp and .shx files, and flush + all outstanding header information to the files. It will also recover + resources associated with the handle. After this call the hSHP handle + cannot be used again.

+ + + +

SHPCreate()

+ +
+SHPHandle SHPCreate( const char * pszShapeFile, int nShapeType );
+
+  pszShapeFile:		The name of the layer to access.  This can be the
+			name of either the .shp or the .shx file or can
+			just be the path plus the basename of the pair.
+
+  nShapeType:		The type of shapes to be stored in the newly created
+			file.  It may be either SHPT_POINT, SHPT_ARC, 
+		        SHPT_POLYGON or SHPT_MULTIPOINT.
+
+ + The SHPCreate() function will create a new .shp and .shx file of the + desired type.

+ + + +

SHPCreateSimpleObject()

+ +
+SHPObject * 
+     SHPCreateSimpleObject( int nSHPType, int nVertices, 
+			    double *padfX, double * padfY, double *padfZ, );
+
+  nSHPType:		The SHPT_ type of the object to be created, such
+                        as SHPT_POINT, or SHPT_POLYGON.
+  
+  nVertices:		The number of vertices being passed in padfX,    
+                        padfY, and padfZ. 
+
+  padfX:		An array of nVertices X coordinates of the vertices
+                        for this object.
+
+  padfY:		An array of nVertices Y coordinates of the vertices
+                        for this object.
+
+  padfZ:		An array of nVertices Z coordinates of the vertices
+                        for this object.  This may be NULL in which case
+		        they are all assumed to be zero.
+
+ + The SHPCreateSimpleObject() allows for the convenient creation of + simple objects. This is normally used so that the SHPObject can be + passed to SHPWriteObject() to write it to the file. The simple object + creation API assumes an M (measure) value of zero for each vertex. For + complex objects (such as polygons) it is assumed that there is only one + part, and that it is of the default type (SHPP_RING).

+ + Use the SHPCreateObject() function for more sophisticated objects. The + SHPDestroyObject() function should be used to free resources associated with + an object allocated with SHPCreateSimpleObject().

+ + This function computes a bounding box for the SHPObject from the given + vertices.

+ + + +

SHPCreateObject()

+ +
+SHPObject * 
+     SHPCreateObject( int nSHPType, int iShape,
+                      int nParts, int * panPartStart, int * panPartType,
+                      int nVertices, double *padfX, double * padfY, 
+                      double *padfZ, double *padfM );
+
+  nSHPType:		The SHPT_ type of the object to be created, such
+                        as SHPT_POINT, or SHPT_POLYGON.
+
+  iShape:		The shapeid to be recorded with this shape.
+
+  nParts:		The number of parts for this object.  If this is
+                        zero for ARC, or POLYGON type objects, a single 
+                        zero valued part will be created internally.
+  
+  panPartStart:		The list of zero based start vertices for the rings
+                        (parts) in this object.  The first should always be
+                        zero.  This may be NULL if nParts is 0.
+  
+  panPartType:		The type of each of the parts.  This is only meaningful
+                        for MULTIPATCH files.  For all other cases this may
+                        be NULL, and will be assumed to be SHPP_RING.
+  
+  nVertices:		The number of vertices being passed in padfX,    
+                        padfY, and padfZ. 
+
+  padfX:		An array of nVertices X coordinates of the vertices
+                        for this object.
+
+  padfY:		An array of nVertices Y coordinates of the vertices
+                        for this object.
+
+  padfZ:		An array of nVertices Z coordinates of the vertices
+                        for this object.  This may be NULL in which case
+		        they are all assumed to be zero.
+
+  padfM:		An array of nVertices M (measure values) of the 
+			vertices for this object.  This may be NULL in which 
+			case they are all assumed to be zero.
+
+ + The SHPCreateSimpleObject() allows for the creation of objects (shapes). + This is normally used so that the SHPObject can be passed to + SHPWriteObject() to write it to the file.

+ + The SHPDestroyObject() function should be used to free resources associated + with an object allocated with SHPCreateObject().

+ + This function computes a bounding box for the SHPObject from the given + vertices.

+ + + +

SHPComputeExtents()

+ +
+void SHPComputeExtents( SHPObject * psObject );
+
+  psObject:		An existing shape object to be updated in place.
+
+ + This function will recompute the extents of this shape, replacing the + existing values of the dfXMin, dfYMin, dfZMin, dfMMin, dfXMax, dfYMax, + dfZMax, and dfMMax values based on the current set of vertices for the + shape. This function is automatically called by SHPCreateObject() but + if the vertices of an existing object are altered it should be called again + to fix up the extents.

+ + + +

SHPWriteObject()

+ +
+int SHPWriteObject( SHPHandle hSHP, int iShape, SHPObject *psObject );
+
+  hSHP:			The handle previously returned by SHPOpen("r+") 
+			or SHPCreate().
+
+  iShape:		The entity number of the shape to write.  A value of
+		        -1 should be used for new shapes.  
+
+  psObject:		The shape to write to the file. This should have
+                        been created with SHPCreateObject(), or 
+                        SHPCreateSimpleObject().
+
+ + The SHPWriteObject() call is used to write a single structure, or entity + to the shapefile. See the definition of the SHPObject structure for + detailed information on fields of a SHPObject. The return value is the + entity number of the written shape.

+ + + +

SHPDestroyObject()

+ +
+void SHPDestroyObject( SHPObject *psObject );
+
+  psObject:		The object to deallocate.
+
+ + This function should be used to deallocate the resources associated with + a SHPObject when it is no longer needed, including those created with + SHPCreateSimpleObject(), SHPCreateObject() and returned from SHPReadObject(). +

+ + + +

SHPRewindObject()

+ +
+int SHPRewindObject( SHPHandle hSHP, SHPObject *psObject );
+
+  hSHP:                 The shapefile (not used at this time).
+  psObject:		The object to deallocate.
+
+ + This function will reverse any rings necessary in order to enforce the + shapefile restrictions on the required order of inner and outer rings in + the Shapefile specification. It returns TRUE if a change is made and FALSE + if no change is made. Only polygon objects will be affected though any + object may be passed. +

+ + + diff --git a/shapelib/shpopen.c b/shapelib/shpopen.c new file mode 100644 index 000000000..54d04a5dc --- /dev/null +++ b/shapelib/shpopen.c @@ -0,0 +1,1872 @@ +/****************************************************************************** + * $Id: shpopen.c,v 1.2 2004/09/27 01:13:58 robertl Exp $ + * + * Project: Shapelib + * Purpose: Implementation of core Shapefile read/write functions. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 1999, 2001, Frank Warmerdam + * + * This software is available under the following "MIT Style" license, + * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This + * option is discussed in more detail in shapelib.html. + * + * -- + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************** + * + * $Log: shpopen.c,v $ + * Revision 1.2 2004/09/27 01:13:58 robertl + * warning fixes in shapelib. From Alexander Stohr. + * + * Revision 1.1 2004/09/20 17:21:22 robertl + * Check in shapelib and experimental prototype of crude shapefile support. + * + * Revision 1.39 2002/08/26 06:46:56 warmerda + * avoid c++ comments + * + * Revision 1.38 2002/05/07 16:43:39 warmerda + * Removed debugging printf. + * + * Revision 1.37 2002/04/10 17:35:22 warmerda + * fixed bug in ring reversal code + * + * Revision 1.36 2002/04/10 16:59:54 warmerda + * added SHPRewindObject + * + * Revision 1.35 2001/12/07 15:10:44 warmerda + * fix if .shx fails to open + * + * Revision 1.34 2001/11/01 16:29:55 warmerda + * move pabyRec into SHPInfo for thread safety + * + * Revision 1.33 2001/07/03 12:18:15 warmerda + * Improved cleanup if SHX not found, provied by Riccardo Cohen. + * + * Revision 1.32 2001/06/22 01:58:07 warmerda + * be more careful about establishing initial bounds in face of NULL shapes + * + * Revision 1.31 2001/05/31 19:35:29 warmerda + * added support for writing null shapes + * + * Revision 1.30 2001/05/28 12:46:29 warmerda + * Add some checking on reasonableness of record count when opening. + * + * Revision 1.29 2001/05/23 13:36:52 warmerda + * added use of SHPAPI_CALL + * + * Revision 1.28 2001/02/06 22:25:06 warmerda + * fixed memory leaks when SHPOpen() fails + * + * Revision 1.27 2000/07/18 15:21:33 warmerda + * added better enforcement of -1 for append in SHPWriteObject + * + * Revision 1.26 2000/02/16 16:03:51 warmerda + * added null shape support + * + * Revision 1.25 1999/12/15 13:47:07 warmerda + * Fixed record size settings in .shp file (was 4 words too long) + * Added stdlib.h. + * + * Revision 1.24 1999/11/05 14:12:04 warmerda + * updated license terms + * + * Revision 1.23 1999/07/27 00:53:46 warmerda + * added support for rewriting shapes + * + * Revision 1.22 1999/06/11 19:19:11 warmerda + * Cleanup pabyRec static buffer on SHPClose(). + * + * Revision 1.21 1999/06/02 14:57:56 kshih + * Remove unused variables + * + * Revision 1.20 1999/04/19 21:04:17 warmerda + * Fixed syntax error. + * + * Revision 1.19 1999/04/19 21:01:57 warmerda + * Force access string to binary in SHPOpen(). + * + * Revision 1.18 1999/04/01 18:48:07 warmerda + * Try upper case extensions if lower case doesn't work. + * + * Revision 1.17 1998/12/31 15:29:39 warmerda + * Disable writing measure values to multipatch objects if + * DISABLE_MULTIPATCH_MEASURE is defined. + * + * Revision 1.16 1998/12/16 05:14:33 warmerda + * Added support to write MULTIPATCH. Fixed reading Z coordinate of + * MULTIPATCH. Fixed record size written for all feature types. + * + * Revision 1.15 1998/12/03 16:35:29 warmerda + * r+b is proper binary access string, not rb+. + * + * Revision 1.14 1998/12/03 15:47:56 warmerda + * Fixed setting of nVertices in SHPCreateObject(). + * + * Revision 1.13 1998/12/03 15:33:54 warmerda + * Made SHPCalculateExtents() separately callable. + * + * Revision 1.12 1998/11/11 20:01:50 warmerda + * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines. + * + * Revision 1.11 1998/11/09 20:56:44 warmerda + * Fixed up handling of file wide bounds. + * + * Revision 1.10 1998/11/09 20:18:51 warmerda + * Converted to support 3D shapefiles, and use of SHPObject. + * + * Revision 1.9 1998/02/24 15:09:05 warmerda + * Fixed memory leak. + * + * Revision 1.8 1997/12/04 15:40:29 warmerda + * Fixed byte swapping of record number, and record length fields in the + * .shp file. + * + * Revision 1.7 1995/10/21 03:15:58 warmerda + * Added support for binary file access, the magic cookie 9997 + * and tried to improve the int32 selection logic for 16bit systems. + * + * Revision 1.6 1995/09/04 04:19:41 warmerda + * Added fix for file bounds. + * + * Revision 1.5 1995/08/25 15:16:44 warmerda + * Fixed a couple of problems with big endian systems ... one with bounds + * and the other with multipart polygons. + * + * Revision 1.4 1995/08/24 18:10:17 warmerda + * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc() + * functions (such as on the Sun). + * + * Revision 1.3 1995/08/23 02:23:15 warmerda + * Added support for reading bounds, and fixed up problems in setting the + * file wide bounds. + * + * Revision 1.2 1995/08/04 03:16:57 warmerda + * Added header. + * + */ + +static char rcsid[] = + "$Id: shpopen.c,v 1.2 2004/09/27 01:13:58 robertl Exp $"; + +#include "shapefil.h" + +#include +#include +#include +#include +#include + +typedef unsigned char uchar; + +#if UINT_MAX == 65535 +typedef long int32; +#else +typedef int int32; +#endif + +#ifndef FALSE +# define FALSE 0 +# define TRUE 1 +#endif + +#define ByteCopy( a, b, c ) memcpy( b, a, c ) +#ifndef MAX +# define MIN(a,b) ((ab) ? a : b) +#endif + +static int bBigEndian; + + +/************************************************************************/ +/* SwapWord() */ +/* */ +/* Swap a 2, 4 or 8 byte word. */ +/************************************************************************/ + +static void SwapWord( int length, void * wordP ) + +{ + int i; + uchar temp; + + for( i=0; i < length/2; i++ ) + { + temp = ((uchar *) wordP)[i]; + ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1]; + ((uchar *) wordP)[length-i-1] = temp; + } +} + +/************************************************************************/ +/* SfRealloc() */ +/* */ +/* A realloc cover function that will access a NULL pointer as */ +/* a valid input. */ +/************************************************************************/ + +static void * SfRealloc( void * pMem, int nNewSize ) + +{ + if( pMem == NULL ) + return( (void *) malloc(nNewSize) ); + else + return( (void *) realloc(pMem,nNewSize) ); +} + +/************************************************************************/ +/* SHPWriteHeader() */ +/* */ +/* Write out a header for the .shp and .shx files as well as the */ +/* contents of the index (.shx) file. */ +/************************************************************************/ + +static void SHPWriteHeader( SHPHandle psSHP ) + +{ + uchar abyHeader[100]; + int i; + int32 i32; + double dValue; + int32 *panSHX; + +/* -------------------------------------------------------------------- */ +/* Prepare header block for .shp file. */ +/* -------------------------------------------------------------------- */ + for( i = 0; i < 100; i++ ) + abyHeader[i] = 0; + + abyHeader[2] = 0x27; /* magic cookie */ + abyHeader[3] = 0x0a; + + i32 = psSHP->nFileSize/2; /* file size */ + ByteCopy( &i32, abyHeader+24, 4 ); + if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); + + i32 = 1000; /* version */ + ByteCopy( &i32, abyHeader+28, 4 ); + if( bBigEndian ) SwapWord( 4, abyHeader+28 ); + + i32 = psSHP->nShapeType; /* shape type */ + ByteCopy( &i32, abyHeader+32, 4 ); + if( bBigEndian ) SwapWord( 4, abyHeader+32 ); + + dValue = psSHP->adBoundsMin[0]; /* set bounds */ + ByteCopy( &dValue, abyHeader+36, 8 ); + if( bBigEndian ) SwapWord( 8, abyHeader+36 ); + + dValue = psSHP->adBoundsMin[1]; + ByteCopy( &dValue, abyHeader+44, 8 ); + if( bBigEndian ) SwapWord( 8, abyHeader+44 ); + + dValue = psSHP->adBoundsMax[0]; + ByteCopy( &dValue, abyHeader+52, 8 ); + if( bBigEndian ) SwapWord( 8, abyHeader+52 ); + + dValue = psSHP->adBoundsMax[1]; + ByteCopy( &dValue, abyHeader+60, 8 ); + if( bBigEndian ) SwapWord( 8, abyHeader+60 ); + + dValue = psSHP->adBoundsMin[2]; /* z */ + ByteCopy( &dValue, abyHeader+68, 8 ); + if( bBigEndian ) SwapWord( 8, abyHeader+68 ); + + dValue = psSHP->adBoundsMax[2]; + ByteCopy( &dValue, abyHeader+76, 8 ); + if( bBigEndian ) SwapWord( 8, abyHeader+76 ); + + dValue = psSHP->adBoundsMin[3]; /* m */ + ByteCopy( &dValue, abyHeader+84, 8 ); + if( bBigEndian ) SwapWord( 8, abyHeader+84 ); + + dValue = psSHP->adBoundsMax[3]; + ByteCopy( &dValue, abyHeader+92, 8 ); + if( bBigEndian ) SwapWord( 8, abyHeader+92 ); + +/* -------------------------------------------------------------------- */ +/* Write .shp file header. */ +/* -------------------------------------------------------------------- */ + fseek( psSHP->fpSHP, 0, 0 ); + fwrite( abyHeader, 100, 1, psSHP->fpSHP ); + +/* -------------------------------------------------------------------- */ +/* Prepare, and write .shx file header. */ +/* -------------------------------------------------------------------- */ + i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2; /* file size */ + ByteCopy( &i32, abyHeader+24, 4 ); + if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); + + fseek( psSHP->fpSHX, 0, 0 ); + fwrite( abyHeader, 100, 1, psSHP->fpSHX ); + +/* -------------------------------------------------------------------- */ +/* Write out the .shx contents. */ +/* -------------------------------------------------------------------- */ + panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords); + + for( i = 0; i < psSHP->nRecords; i++ ) + { + panSHX[i*2 ] = psSHP->panRecOffset[i]/2; + panSHX[i*2+1] = psSHP->panRecSize[i]/2; + if( !bBigEndian ) SwapWord( 4, panSHX+i*2 ); + if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 ); + } + + fwrite( panSHX, sizeof(int32) * 2, psSHP->nRecords, psSHP->fpSHX ); + + free( panSHX ); +} + +/************************************************************************/ +/* SHPOpen() */ +/* */ +/* Open the .shp and .shx files based on the basename of the */ +/* files or either file name. */ +/************************************************************************/ + +SHPHandle SHPAPI_CALL +SHPOpen( const char * pszLayer, const char * pszAccess ) + +{ + char *pszFullname, *pszBasename; + SHPHandle psSHP; + + uchar *pabyBuf; + int i; + double dValue; + +/* -------------------------------------------------------------------- */ +/* Ensure the access string is one of the legal ones. We */ +/* ensure the result string indicates binary to avoid common */ +/* problems on Windows. */ +/* -------------------------------------------------------------------- */ + if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0 + || strcmp(pszAccess,"r+") == 0 ) + pszAccess = "r+b"; + else + pszAccess = "rb"; + +/* -------------------------------------------------------------------- */ +/* Establish the byte order on this machine. */ +/* -------------------------------------------------------------------- */ + i = 1; + if( *((uchar *) &i) == 1 ) + bBigEndian = FALSE; + else + bBigEndian = TRUE; + +/* -------------------------------------------------------------------- */ +/* Initialize the info structure. */ +/* -------------------------------------------------------------------- */ + psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1); + + psSHP->bUpdated = FALSE; + +/* -------------------------------------------------------------------- */ +/* Compute the base (layer) name. If there is any extension */ +/* on the passed in filename we will strip it off. */ +/* -------------------------------------------------------------------- */ + pszBasename = (char *) malloc(strlen(pszLayer)+5); + strcpy( pszBasename, pszLayer ); + for( i = strlen(pszBasename)-1; + i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' + && pszBasename[i] != '\\'; + i-- ) {} + + if( pszBasename[i] == '.' ) + pszBasename[i] = '\0'; + +/* -------------------------------------------------------------------- */ +/* Open the .shp and .shx files. Note that files pulled from */ +/* a PC to Unix with upper case filenames won't work! */ +/* -------------------------------------------------------------------- */ + pszFullname = (char *) malloc(strlen(pszBasename) + 5); + sprintf( pszFullname, "%s.shp", pszBasename ); + psSHP->fpSHP = fopen(pszFullname, pszAccess ); + if( psSHP->fpSHP == NULL ) + { + sprintf( pszFullname, "%s.SHP", pszBasename ); + psSHP->fpSHP = fopen(pszFullname, pszAccess ); + } + + if( psSHP->fpSHP == NULL ) + { + free( psSHP ); + free( pszBasename ); + free( pszFullname ); + return( NULL ); + } + + sprintf( pszFullname, "%s.shx", pszBasename ); + psSHP->fpSHX = fopen(pszFullname, pszAccess ); + if( psSHP->fpSHX == NULL ) + { + sprintf( pszFullname, "%s.SHX", pszBasename ); + psSHP->fpSHX = fopen(pszFullname, pszAccess ); + } + + if( psSHP->fpSHX == NULL ) + { + fclose( psSHP->fpSHP ); + free( psSHP ); + free( pszBasename ); + free( pszFullname ); + return( NULL ); + } + + free( pszFullname ); + free( pszBasename ); + +/* -------------------------------------------------------------------- */ +/* Read the file size from the SHP file. */ +/* -------------------------------------------------------------------- */ + pabyBuf = (uchar *) malloc(100); + fread( pabyBuf, 100, 1, psSHP->fpSHP ); + + psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256 + + pabyBuf[25] * 256 * 256 + + pabyBuf[26] * 256 + + pabyBuf[27]) * 2; + +/* -------------------------------------------------------------------- */ +/* Read SHX file Header info */ +/* -------------------------------------------------------------------- */ + fread( pabyBuf, 100, 1, psSHP->fpSHX ); + + if( pabyBuf[0] != 0 + || pabyBuf[1] != 0 + || pabyBuf[2] != 0x27 + || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) ) + { + fclose( psSHP->fpSHP ); + fclose( psSHP->fpSHX ); + free( psSHP ); + + return( NULL ); + } + + psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256 + + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256; + psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8; + + psSHP->nShapeType = pabyBuf[32]; + + if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 ) + { + /* this header appears to be corrupt. Give up. */ + fclose( psSHP->fpSHP ); + fclose( psSHP->fpSHX ); + free( psSHP ); + + return( NULL ); + } + +/* -------------------------------------------------------------------- */ +/* Read the bounds. */ +/* -------------------------------------------------------------------- */ + if( bBigEndian ) SwapWord( 8, pabyBuf+36 ); + memcpy( &dValue, pabyBuf+36, 8 ); + psSHP->adBoundsMin[0] = dValue; + + if( bBigEndian ) SwapWord( 8, pabyBuf+44 ); + memcpy( &dValue, pabyBuf+44, 8 ); + psSHP->adBoundsMin[1] = dValue; + + if( bBigEndian ) SwapWord( 8, pabyBuf+52 ); + memcpy( &dValue, pabyBuf+52, 8 ); + psSHP->adBoundsMax[0] = dValue; + + if( bBigEndian ) SwapWord( 8, pabyBuf+60 ); + memcpy( &dValue, pabyBuf+60, 8 ); + psSHP->adBoundsMax[1] = dValue; + + if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */ + memcpy( &dValue, pabyBuf+68, 8 ); + psSHP->adBoundsMin[2] = dValue; + + if( bBigEndian ) SwapWord( 8, pabyBuf+76 ); + memcpy( &dValue, pabyBuf+76, 8 ); + psSHP->adBoundsMax[2] = dValue; + + if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */ + memcpy( &dValue, pabyBuf+84, 8 ); + psSHP->adBoundsMin[3] = dValue; + + if( bBigEndian ) SwapWord( 8, pabyBuf+92 ); + memcpy( &dValue, pabyBuf+92, 8 ); + psSHP->adBoundsMax[3] = dValue; + + free( pabyBuf ); + +/* -------------------------------------------------------------------- */ +/* Read the .shx file to get the offsets to each record in */ +/* the .shp file. */ +/* -------------------------------------------------------------------- */ + psSHP->nMaxRecords = psSHP->nRecords; + + psSHP->panRecOffset = + (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) ); + psSHP->panRecSize = + (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) ); + + pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) ); + fread( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ); + + for( i = 0; i < psSHP->nRecords; i++ ) + { + int32 nOffset, nLength; + + memcpy( &nOffset, pabyBuf + i * 8, 4 ); + if( !bBigEndian ) SwapWord( 4, &nOffset ); + + memcpy( &nLength, pabyBuf + i * 8 + 4, 4 ); + if( !bBigEndian ) SwapWord( 4, &nLength ); + + psSHP->panRecOffset[i] = nOffset*2; + psSHP->panRecSize[i] = nLength*2; + } + free( pabyBuf ); + + return( psSHP ); +} + +/************************************************************************/ +/* SHPClose() */ +/* */ +/* Close the .shp and .shx files. */ +/************************************************************************/ + +void SHPAPI_CALL +SHPClose(SHPHandle psSHP ) + +{ +/* -------------------------------------------------------------------- */ +/* Update the header if we have modified anything. */ +/* -------------------------------------------------------------------- */ + if( psSHP->bUpdated ) + { + SHPWriteHeader( psSHP ); + } + +/* -------------------------------------------------------------------- */ +/* Free all resources, and close files. */ +/* -------------------------------------------------------------------- */ + free( psSHP->panRecOffset ); + free( psSHP->panRecSize ); + + fclose( psSHP->fpSHX ); + fclose( psSHP->fpSHP ); + + if( psSHP->pabyRec != NULL ) + { + free( psSHP->pabyRec ); + } + + free( psSHP ); +} + +/************************************************************************/ +/* SHPGetInfo() */ +/* */ +/* Fetch general information about the shape file. */ +/************************************************************************/ + +void SHPAPI_CALL +SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType, + double * padfMinBound, double * padfMaxBound ) + +{ + int i; + + if( pnEntities != NULL ) + *pnEntities = psSHP->nRecords; + + if( pnShapeType != NULL ) + *pnShapeType = psSHP->nShapeType; + + for( i = 0; i < 4; i++ ) + { + if( padfMinBound != NULL ) + padfMinBound[i] = psSHP->adBoundsMin[i]; + if( padfMaxBound != NULL ) + padfMaxBound[i] = psSHP->adBoundsMax[i]; + } +} + +/************************************************************************/ +/* SHPCreate() */ +/* */ +/* Create a new shape file and return a handle to the open */ +/* shape file with read/write access. */ +/************************************************************************/ + +SHPHandle SHPAPI_CALL +SHPCreate( const char * pszLayer, int nShapeType ) + +{ + char *pszBasename, *pszFullname; + int i; + FILE *fpSHP, *fpSHX; + uchar abyHeader[100]; + int32 i32; + double dValue; + +/* -------------------------------------------------------------------- */ +/* Establish the byte order on this system. */ +/* -------------------------------------------------------------------- */ + i = 1; + if( *((uchar *) &i) == 1 ) + bBigEndian = FALSE; + else + bBigEndian = TRUE; + +/* -------------------------------------------------------------------- */ +/* Compute the base (layer) name. If there is any extension */ +/* on the passed in filename we will strip it off. */ +/* -------------------------------------------------------------------- */ + pszBasename = (char *) malloc(strlen(pszLayer)+5); + strcpy( pszBasename, pszLayer ); + for( i = strlen(pszBasename)-1; + i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' + && pszBasename[i] != '\\'; + i-- ) {} + + if( pszBasename[i] == '.' ) + pszBasename[i] = '\0'; + +/* -------------------------------------------------------------------- */ +/* Open the two files so we can write their headers. */ +/* -------------------------------------------------------------------- */ + pszFullname = (char *) malloc(strlen(pszBasename) + 5); + sprintf( pszFullname, "%s.shp", pszBasename ); + fpSHP = fopen(pszFullname, "wb" ); + if( fpSHP == NULL ) + return( NULL ); + + sprintf( pszFullname, "%s.shx", pszBasename ); + fpSHX = fopen(pszFullname, "wb" ); + if( fpSHX == NULL ) + return( NULL ); + + free( pszFullname ); + free( pszBasename ); + +/* -------------------------------------------------------------------- */ +/* Prepare header block for .shp file. */ +/* -------------------------------------------------------------------- */ + for( i = 0; i < 100; i++ ) + abyHeader[i] = 0; + + abyHeader[2] = 0x27; /* magic cookie */ + abyHeader[3] = 0x0a; + + i32 = 50; /* file size */ + ByteCopy( &i32, abyHeader+24, 4 ); + if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); + + i32 = 1000; /* version */ + ByteCopy( &i32, abyHeader+28, 4 ); + if( bBigEndian ) SwapWord( 4, abyHeader+28 ); + + i32 = nShapeType; /* shape type */ + ByteCopy( &i32, abyHeader+32, 4 ); + if( bBigEndian ) SwapWord( 4, abyHeader+32 ); + + dValue = 0.0; /* set bounds */ + ByteCopy( &dValue, abyHeader+36, 8 ); + ByteCopy( &dValue, abyHeader+44, 8 ); + ByteCopy( &dValue, abyHeader+52, 8 ); + ByteCopy( &dValue, abyHeader+60, 8 ); + +/* -------------------------------------------------------------------- */ +/* Write .shp file header. */ +/* -------------------------------------------------------------------- */ + fwrite( abyHeader, 100, 1, fpSHP ); + +/* -------------------------------------------------------------------- */ +/* Prepare, and write .shx file header. */ +/* -------------------------------------------------------------------- */ + i32 = 50; /* file size */ + ByteCopy( &i32, abyHeader+24, 4 ); + if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); + + fwrite( abyHeader, 100, 1, fpSHX ); + +/* -------------------------------------------------------------------- */ +/* Close the files, and then open them as regular existing files. */ +/* -------------------------------------------------------------------- */ + fclose( fpSHP ); + fclose( fpSHX ); + + return( SHPOpen( pszLayer, "r+b" ) ); +} + +/************************************************************************/ +/* _SHPSetBounds() */ +/* */ +/* Compute a bounds rectangle for a shape, and set it into the */ +/* indicated location in the record. */ +/************************************************************************/ + +static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape ) + +{ + ByteCopy( &(psShape->dfXMin), pabyRec + 0, 8 ); + ByteCopy( &(psShape->dfYMin), pabyRec + 8, 8 ); + ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 ); + ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 ); + + if( bBigEndian ) + { + SwapWord( 8, pabyRec + 0 ); + SwapWord( 8, pabyRec + 8 ); + SwapWord( 8, pabyRec + 16 ); + SwapWord( 8, pabyRec + 24 ); + } +} + +/************************************************************************/ +/* SHPComputeExtents() */ +/* */ +/* Recompute the extents of a shape. Automatically done by */ +/* SHPCreateObject(). */ +/************************************************************************/ + +void SHPAPI_CALL +SHPComputeExtents( SHPObject * psObject ) + +{ + int i; + +/* -------------------------------------------------------------------- */ +/* Build extents for this object. */ +/* -------------------------------------------------------------------- */ + if( psObject->nVertices > 0 ) + { + psObject->dfXMin = psObject->dfXMax = psObject->padfX[0]; + psObject->dfYMin = psObject->dfYMax = psObject->padfY[0]; + psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0]; + psObject->dfMMin = psObject->dfMMax = psObject->padfM[0]; + } + + for( i = 0; i < psObject->nVertices; i++ ) + { + psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]); + psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]); + psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]); + psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]); + + psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]); + psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]); + psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]); + psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]); + } +} + +/************************************************************************/ +/* SHPCreateObject() */ +/* */ +/* Create a shape object. It should be freed with */ +/* SHPDestroyObject(). */ +/************************************************************************/ + +SHPObject SHPAPI_CALL1(*) +SHPCreateObject( int nSHPType, int nShapeId, int nParts, + int * panPartStart, int * panPartType, + int nVertices, const double * padfX, const double * padfY, + const double * padfZ, const double * padfM ) + +{ + SHPObject *psObject; + int i, bHasM, bHasZ; + + psObject = (SHPObject *) calloc(1,sizeof(SHPObject)); + psObject->nSHPType = nSHPType; + psObject->nShapeId = nShapeId; + +/* -------------------------------------------------------------------- */ +/* Establish whether this shape type has M, and Z values. */ +/* -------------------------------------------------------------------- */ + if( nSHPType == SHPT_ARCM + || nSHPType == SHPT_POINTM + || nSHPType == SHPT_POLYGONM + || nSHPType == SHPT_MULTIPOINTM ) + { + bHasM = TRUE; + bHasZ = FALSE; + } + else if( nSHPType == SHPT_ARCZ + || nSHPType == SHPT_POINTZ + || nSHPType == SHPT_POLYGONZ + || nSHPType == SHPT_MULTIPOINTZ + || nSHPType == SHPT_MULTIPATCH ) + { + bHasM = TRUE; + bHasZ = TRUE; + } + else + { + bHasM = FALSE; + bHasZ = FALSE; + } + +/* -------------------------------------------------------------------- */ +/* Capture parts. Note that part type is optional, and */ +/* defaults to ring. */ +/* -------------------------------------------------------------------- */ + if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON + || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM + || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ + || nSHPType == SHPT_MULTIPATCH ) + { + psObject->nParts = MAX(1,nParts); + + psObject->panPartStart = (int *) + malloc(sizeof(int) * psObject->nParts); + psObject->panPartType = (int *) + malloc(sizeof(int) * psObject->nParts); + + psObject->panPartStart[0] = 0; + psObject->panPartType[0] = SHPP_RING; + + for( i = 0; i < nParts; i++ ) + { + psObject->panPartStart[i] = panPartStart[i]; + if( panPartType != NULL ) + psObject->panPartType[i] = panPartType[i]; + else + psObject->panPartType[i] = SHPP_RING; + } + } + +/* -------------------------------------------------------------------- */ +/* Capture vertices. Note that Z and M are optional, but X and */ +/* Y are not. */ +/* -------------------------------------------------------------------- */ + if( nVertices > 0 ) + { + psObject->padfX = (double *) calloc(sizeof(double),nVertices); + psObject->padfY = (double *) calloc(sizeof(double),nVertices); + psObject->padfZ = (double *) calloc(sizeof(double),nVertices); + psObject->padfM = (double *) calloc(sizeof(double),nVertices); + + assert( padfX != NULL ); + assert( padfY != NULL ); + + for( i = 0; i < nVertices; i++ ) + { + psObject->padfX[i] = padfX[i]; + psObject->padfY[i] = padfY[i]; + if( padfZ != NULL && bHasZ ) + psObject->padfZ[i] = padfZ[i]; + if( padfM != NULL && bHasM ) + psObject->padfM[i] = padfM[i]; + } + } + +/* -------------------------------------------------------------------- */ +/* Compute the extents. */ +/* -------------------------------------------------------------------- */ + psObject->nVertices = nVertices; + SHPComputeExtents( psObject ); + + return( psObject ); +} + +/************************************************************************/ +/* SHPCreateSimpleObject() */ +/* */ +/* Create a simple (common) shape object. Destroy with */ +/* SHPDestroyObject(). */ +/************************************************************************/ + +SHPObject SHPAPI_CALL1(*) +SHPCreateSimpleObject( int nSHPType, int nVertices, + const double * padfX, const double * padfY, + const double * padfZ ) + +{ + return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL, + nVertices, padfX, padfY, padfZ, NULL ) ); +} + +/************************************************************************/ +/* SHPWriteObject() */ +/* */ +/* Write out the vertices of a new structure. Note that it is */ +/* only possible to write vertices at the end of the file. */ +/************************************************************************/ + +int SHPAPI_CALL +SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject ) + +{ + int nRecordOffset, i, nRecordSize; + uchar *pabyRec; + int32 i32; + + psSHP->bUpdated = TRUE; + +/* -------------------------------------------------------------------- */ +/* Ensure that shape object matches the type of the file it is */ +/* being written to. */ +/* -------------------------------------------------------------------- */ + assert( psObject->nSHPType == psSHP->nShapeType + || psObject->nSHPType == SHPT_NULL ); + +/* -------------------------------------------------------------------- */ +/* Ensure that -1 is used for appends. Either blow an */ +/* assertion, or if they are disabled, set the shapeid to -1 */ +/* for appends. */ +/* -------------------------------------------------------------------- */ + assert( nShapeId == -1 + || (nShapeId >= 0 && nShapeId < psSHP->nRecords) ); + + if( nShapeId != -1 && nShapeId >= psSHP->nRecords ) + nShapeId = -1; + +/* -------------------------------------------------------------------- */ +/* Add the new entity to the in memory index. */ +/* -------------------------------------------------------------------- */ + if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords ) + { + psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100); + + psSHP->panRecOffset = (int *) + SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords ); + psSHP->panRecSize = (int *) + SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords ); + } + +/* -------------------------------------------------------------------- */ +/* Initialize record. */ +/* -------------------------------------------------------------------- */ + pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double) + + psObject->nParts * 8 + 128); + +/* -------------------------------------------------------------------- */ +/* Extract vertices for a Polygon or Arc. */ +/* -------------------------------------------------------------------- */ + if( psObject->nSHPType == SHPT_POLYGON + || psObject->nSHPType == SHPT_POLYGONZ + || psObject->nSHPType == SHPT_POLYGONM + || psObject->nSHPType == SHPT_ARC + || psObject->nSHPType == SHPT_ARCZ + || psObject->nSHPType == SHPT_ARCM + || psObject->nSHPType == SHPT_MULTIPATCH ) + { + int32 nPoints, nParts; + int i; + + nPoints = psObject->nVertices; + nParts = psObject->nParts; + + _SHPSetBounds( pabyRec + 12, psObject ); + + if( bBigEndian ) SwapWord( 4, &nPoints ); + if( bBigEndian ) SwapWord( 4, &nParts ); + + ByteCopy( &nPoints, pabyRec + 40 + 8, 4 ); + ByteCopy( &nParts, pabyRec + 36 + 8, 4 ); + + nRecordSize = 52; + + /* + * Write part start positions. + */ + ByteCopy( psObject->panPartStart, pabyRec + 44 + 8, + 4 * psObject->nParts ); + for( i = 0; i < psObject->nParts; i++ ) + { + if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i ); + nRecordSize += 4; + } + + /* + * Write multipatch part types if needed. + */ + if( psObject->nSHPType == SHPT_MULTIPATCH ) + { + memcpy( pabyRec + nRecordSize, psObject->panPartType, + 4*psObject->nParts ); + for( i = 0; i < psObject->nParts; i++ ) + { + if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize ); + nRecordSize += 4; + } + } + + /* + * Write the (x,y) vertex values. + */ + for( i = 0; i < psObject->nVertices; i++ ) + { + ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 ); + ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 ); + + if( bBigEndian ) + SwapWord( 8, pabyRec + nRecordSize ); + + if( bBigEndian ) + SwapWord( 8, pabyRec + nRecordSize + 8 ); + + nRecordSize += 2 * 8; + } + + /* + * Write the Z coordinates (if any). + */ + if( psObject->nSHPType == SHPT_POLYGONZ + || psObject->nSHPType == SHPT_ARCZ + || psObject->nSHPType == SHPT_MULTIPATCH ) + { + ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + + ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + + for( i = 0; i < psObject->nVertices; i++ ) + { + ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + } + } + + /* + * Write the M values, if any. + */ + if( psObject->nSHPType == SHPT_POLYGONM + || psObject->nSHPType == SHPT_ARCM +#ifndef DISABLE_MULTIPATCH_MEASURE + || psObject->nSHPType == SHPT_MULTIPATCH +#endif + || psObject->nSHPType == SHPT_POLYGONZ + || psObject->nSHPType == SHPT_ARCZ ) + { + ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + + ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + + for( i = 0; i < psObject->nVertices; i++ ) + { + ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + } + } + } + +/* -------------------------------------------------------------------- */ +/* Extract vertices for a MultiPoint. */ +/* -------------------------------------------------------------------- */ + else if( psObject->nSHPType == SHPT_MULTIPOINT + || psObject->nSHPType == SHPT_MULTIPOINTZ + || psObject->nSHPType == SHPT_MULTIPOINTM ) + { + int32 nPoints; + int i; + + nPoints = psObject->nVertices; + + _SHPSetBounds( pabyRec + 12, psObject ); + + if( bBigEndian ) SwapWord( 4, &nPoints ); + ByteCopy( &nPoints, pabyRec + 44, 4 ); + + for( i = 0; i < psObject->nVertices; i++ ) + { + ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 ); + ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 ); + + if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 ); + if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 ); + } + + nRecordSize = 48 + 16 * psObject->nVertices; + + if( psObject->nSHPType == SHPT_MULTIPOINTZ ) + { + ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + + ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + + for( i = 0; i < psObject->nVertices; i++ ) + { + ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + } + } + + if( psObject->nSHPType == SHPT_MULTIPOINTZ + || psObject->nSHPType == SHPT_MULTIPOINTM ) + { + ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + + ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + + for( i = 0; i < psObject->nVertices; i++ ) + { + ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + } + } + } + +/* -------------------------------------------------------------------- */ +/* Write point. */ +/* -------------------------------------------------------------------- */ + else if( psObject->nSHPType == SHPT_POINT + || psObject->nSHPType == SHPT_POINTZ + || psObject->nSHPType == SHPT_POINTM ) + { + ByteCopy( psObject->padfX, pabyRec + 12, 8 ); + ByteCopy( psObject->padfY, pabyRec + 20, 8 ); + + if( bBigEndian ) SwapWord( 8, pabyRec + 12 ); + if( bBigEndian ) SwapWord( 8, pabyRec + 20 ); + + nRecordSize = 28; + + if( psObject->nSHPType == SHPT_POINTZ ) + { + ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + } + + if( psObject->nSHPType == SHPT_POINTZ + || psObject->nSHPType == SHPT_POINTM ) + { + ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 ); + if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); + nRecordSize += 8; + } + } + +/* -------------------------------------------------------------------- */ +/* Not much to do for null geometries. */ +/* -------------------------------------------------------------------- */ + else if( psObject->nSHPType == SHPT_NULL ) + { + nRecordSize = 12; + } + + else + { + /* unknown type */ + assert( FALSE ); + } + +/* -------------------------------------------------------------------- */ +/* Establish where we are going to put this record. If we are */ +/* rewriting and existing record, and it will fit, then put it */ +/* back where the original came from. Otherwise write at the end. */ +/* -------------------------------------------------------------------- */ + if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 ) + { + if( nShapeId == -1 ) + nShapeId = psSHP->nRecords++; + + psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize; + psSHP->panRecSize[nShapeId] = nRecordSize-8; + psSHP->nFileSize += nRecordSize; + } + else + { + nRecordOffset = psSHP->panRecOffset[nShapeId]; + } + +/* -------------------------------------------------------------------- */ +/* Set the shape type, record number, and record size. */ +/* -------------------------------------------------------------------- */ + i32 = nShapeId+1; /* record # */ + if( !bBigEndian ) SwapWord( 4, &i32 ); + ByteCopy( &i32, pabyRec, 4 ); + + i32 = (nRecordSize-8)/2; /* record size */ + if( !bBigEndian ) SwapWord( 4, &i32 ); + ByteCopy( &i32, pabyRec + 4, 4 ); + + i32 = psObject->nSHPType; /* shape type */ + if( bBigEndian ) SwapWord( 4, &i32 ); + ByteCopy( &i32, pabyRec + 8, 4 ); + +/* -------------------------------------------------------------------- */ +/* Write out record. */ +/* -------------------------------------------------------------------- */ + if( fseek( psSHP->fpSHP, nRecordOffset, 0 ) != 0 + || fwrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 ) + { + printf( "Error in fseek() or fwrite().\n" ); + free( pabyRec ); + return -1; + } + + free( pabyRec ); + +/* -------------------------------------------------------------------- */ +/* Expand file wide bounds based on this shape. */ +/* -------------------------------------------------------------------- */ + if( psSHP->adBoundsMin[0] == 0.0 + && psSHP->adBoundsMax[0] == 0.0 + && psSHP->adBoundsMin[1] == 0.0 + && psSHP->adBoundsMax[1] == 0.0 + && psObject->nSHPType != SHPT_NULL ) + { + psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0]; + psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0]; + psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0]; + psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0]; + } + + for( i = 0; i < psObject->nVertices; i++ ) + { + psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]); + psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]); + psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]); + psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]); + psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]); + psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]); + psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]); + psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]); + } + + return( nShapeId ); +} + +/************************************************************************/ +/* SHPReadObject() */ +/* */ +/* Read the vertices, parts, and other non-attribute information */ +/* for one shape. */ +/************************************************************************/ + +SHPObject SHPAPI_CALL1(*) +SHPReadObject( SHPHandle psSHP, int hEntity ) + +{ + SHPObject *psShape; + +/* -------------------------------------------------------------------- */ +/* Validate the record/entity number. */ +/* -------------------------------------------------------------------- */ + if( hEntity < 0 || hEntity >= psSHP->nRecords ) + return( NULL ); + +/* -------------------------------------------------------------------- */ +/* Ensure our record buffer is large enough. */ +/* -------------------------------------------------------------------- */ + if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize ) + { + psSHP->nBufSize = psSHP->panRecSize[hEntity]+8; + psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize); + } + +/* -------------------------------------------------------------------- */ +/* Read the record. */ +/* -------------------------------------------------------------------- */ + fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ); + fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP ); + +/* -------------------------------------------------------------------- */ +/* Allocate and minimally initialize the object. */ +/* -------------------------------------------------------------------- */ + psShape = (SHPObject *) calloc(1,sizeof(SHPObject)); + psShape->nShapeId = hEntity; + + memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 ); + if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) ); + +/* ==================================================================== */ +/* Extract vertices for a Polygon or Arc. */ +/* ==================================================================== */ + if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC + || psShape->nSHPType == SHPT_POLYGONZ + || psShape->nSHPType == SHPT_POLYGONM + || psShape->nSHPType == SHPT_ARCZ + || psShape->nSHPType == SHPT_ARCM + || psShape->nSHPType == SHPT_MULTIPATCH ) + { + int32 nPoints, nParts; + int i, nOffset; + +/* -------------------------------------------------------------------- */ +/* Get the X/Y bounds. */ +/* -------------------------------------------------------------------- */ + memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 ); + memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 ); + memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 ); + memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 ); + + if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) ); + if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) ); + if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) ); + if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) ); + +/* -------------------------------------------------------------------- */ +/* Extract part/point count, and build vertex and part arrays */ +/* to proper size. */ +/* -------------------------------------------------------------------- */ + memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 ); + memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 ); + + if( bBigEndian ) SwapWord( 4, &nPoints ); + if( bBigEndian ) SwapWord( 4, &nParts ); + + psShape->nVertices = nPoints; + psShape->padfX = (double *) calloc(nPoints,sizeof(double)); + psShape->padfY = (double *) calloc(nPoints,sizeof(double)); + psShape->padfZ = (double *) calloc(nPoints,sizeof(double)); + psShape->padfM = (double *) calloc(nPoints,sizeof(double)); + + psShape->nParts = nParts; + psShape->panPartStart = (int *) calloc(nParts,sizeof(int)); + psShape->panPartType = (int *) calloc(nParts,sizeof(int)); + + for( i = 0; i < nParts; i++ ) + psShape->panPartType[i] = SHPP_RING; + +/* -------------------------------------------------------------------- */ +/* Copy out the part array from the record. */ +/* -------------------------------------------------------------------- */ + memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts ); + for( i = 0; i < nParts; i++ ) + { + if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i ); + } + + nOffset = 44 + 8 + 4*nParts; + +/* -------------------------------------------------------------------- */ +/* If this is a multipatch, we will also have parts types. */ +/* -------------------------------------------------------------------- */ + if( psShape->nSHPType == SHPT_MULTIPATCH ) + { + memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts ); + for( i = 0; i < nParts; i++ ) + { + if( bBigEndian ) SwapWord( 4, psShape->panPartType+i ); + } + + nOffset += 4*nParts; + } + +/* -------------------------------------------------------------------- */ +/* Copy out the vertices from the record. */ +/* -------------------------------------------------------------------- */ + for( i = 0; i < nPoints; i++ ) + { + memcpy(psShape->padfX + i, + psSHP->pabyRec + nOffset + i * 16, + 8 ); + + memcpy(psShape->padfY + i, + psSHP->pabyRec + nOffset + i * 16 + 8, + 8 ); + + if( bBigEndian ) SwapWord( 8, psShape->padfX + i ); + if( bBigEndian ) SwapWord( 8, psShape->padfY + i ); + } + + nOffset += 16*nPoints; + +/* -------------------------------------------------------------------- */ +/* If we have a Z coordinate, collect that now. */ +/* -------------------------------------------------------------------- */ + if( psShape->nSHPType == SHPT_POLYGONZ + || psShape->nSHPType == SHPT_ARCZ + || psShape->nSHPType == SHPT_MULTIPATCH ) + { + memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 ); + memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 ); + + if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) ); + if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) ); + + for( i = 0; i < nPoints; i++ ) + { + memcpy( psShape->padfZ + i, + psSHP->pabyRec + nOffset + 16 + i*8, 8 ); + if( bBigEndian ) SwapWord( 8, psShape->padfZ + i ); + } + + nOffset += 16 + 8*nPoints; + } + +/* -------------------------------------------------------------------- */ +/* If we have a M measure value, then read it now. We assume */ +/* that the measure can be present for any shape if the size is */ +/* big enough, but really it will only occur for the Z shapes */ +/* (options), and the M shapes. */ +/* -------------------------------------------------------------------- */ + if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints ) + { + memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 ); + memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 ); + + if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) ); + if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) ); + + for( i = 0; i < nPoints; i++ ) + { + memcpy( psShape->padfM + i, + psSHP->pabyRec + nOffset + 16 + i*8, 8 ); + if( bBigEndian ) SwapWord( 8, psShape->padfM + i ); + } + } + + } + +/* ==================================================================== */ +/* Extract vertices for a MultiPoint. */ +/* ==================================================================== */ + else if( psShape->nSHPType == SHPT_MULTIPOINT + || psShape->nSHPType == SHPT_MULTIPOINTM + || psShape->nSHPType == SHPT_MULTIPOINTZ ) + { + int32 nPoints; + int i, nOffset; + + memcpy( &nPoints, psSHP->pabyRec + 44, 4 ); + if( bBigEndian ) SwapWord( 4, &nPoints ); + + psShape->nVertices = nPoints; + psShape->padfX = (double *) calloc(nPoints,sizeof(double)); + psShape->padfY = (double *) calloc(nPoints,sizeof(double)); + psShape->padfZ = (double *) calloc(nPoints,sizeof(double)); + psShape->padfM = (double *) calloc(nPoints,sizeof(double)); + + for( i = 0; i < nPoints; i++ ) + { + memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 ); + memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 ); + + if( bBigEndian ) SwapWord( 8, psShape->padfX + i ); + if( bBigEndian ) SwapWord( 8, psShape->padfY + i ); + } + + nOffset = 48 + 16*nPoints; + +/* -------------------------------------------------------------------- */ +/* Get the X/Y bounds. */ +/* -------------------------------------------------------------------- */ + memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 ); + memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 ); + memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 ); + memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 ); + + if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) ); + if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) ); + if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) ); + if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) ); + +/* -------------------------------------------------------------------- */ +/* If we have a Z coordinate, collect that now. */ +/* -------------------------------------------------------------------- */ + if( psShape->nSHPType == SHPT_MULTIPOINTZ ) + { + memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 ); + memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 ); + + if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) ); + if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) ); + + for( i = 0; i < nPoints; i++ ) + { + memcpy( psShape->padfZ + i, + psSHP->pabyRec + nOffset + 16 + i*8, 8 ); + if( bBigEndian ) SwapWord( 8, psShape->padfZ + i ); + } + + nOffset += 16 + 8*nPoints; + } + +/* -------------------------------------------------------------------- */ +/* If we have a M measure value, then read it now. We assume */ +/* that the measure can be present for any shape if the size is */ +/* big enough, but really it will only occur for the Z shapes */ +/* (options), and the M shapes. */ +/* -------------------------------------------------------------------- */ + if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints ) + { + memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 ); + memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 ); + + if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) ); + if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) ); + + for( i = 0; i < nPoints; i++ ) + { + memcpy( psShape->padfM + i, + psSHP->pabyRec + nOffset + 16 + i*8, 8 ); + if( bBigEndian ) SwapWord( 8, psShape->padfM + i ); + } + } + } + +/* ==================================================================== */ +/* Extract vertices for a point. */ +/* ==================================================================== */ + else if( psShape->nSHPType == SHPT_POINT + || psShape->nSHPType == SHPT_POINTM + || psShape->nSHPType == SHPT_POINTZ ) + { + int nOffset; + + psShape->nVertices = 1; + psShape->padfX = (double *) calloc(1,sizeof(double)); + psShape->padfY = (double *) calloc(1,sizeof(double)); + psShape->padfZ = (double *) calloc(1,sizeof(double)); + psShape->padfM = (double *) calloc(1,sizeof(double)); + + memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 ); + memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 ); + + if( bBigEndian ) SwapWord( 8, psShape->padfX ); + if( bBigEndian ) SwapWord( 8, psShape->padfY ); + + nOffset = 20 + 8; + +/* -------------------------------------------------------------------- */ +/* If we have a Z coordinate, collect that now. */ +/* -------------------------------------------------------------------- */ + if( psShape->nSHPType == SHPT_POINTZ ) + { + memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 ); + + if( bBigEndian ) SwapWord( 8, psShape->padfZ ); + + nOffset += 8; + } + +/* -------------------------------------------------------------------- */ +/* If we have a M measure value, then read it now. We assume */ +/* that the measure can be present for any shape if the size is */ +/* big enough, but really it will only occur for the Z shapes */ +/* (options), and the M shapes. */ +/* -------------------------------------------------------------------- */ + if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 ) + { + memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 ); + + if( bBigEndian ) SwapWord( 8, psShape->padfM ); + } + +/* -------------------------------------------------------------------- */ +/* Since no extents are supplied in the record, we will apply */ +/* them from the single vertex. */ +/* -------------------------------------------------------------------- */ + psShape->dfXMin = psShape->dfXMax = psShape->padfX[0]; + psShape->dfYMin = psShape->dfYMax = psShape->padfY[0]; + psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0]; + psShape->dfMMin = psShape->dfMMax = psShape->padfM[0]; + } + + return( psShape ); +} + +/************************************************************************/ +/* SHPTypeName() */ +/************************************************************************/ + +const char SHPAPI_CALL1(*) +SHPTypeName( int nSHPType ) + +{ + switch( nSHPType ) + { + case SHPT_NULL: + return "NullShape"; + + case SHPT_POINT: + return "Point"; + + case SHPT_ARC: + return "Arc"; + + case SHPT_POLYGON: + return "Polygon"; + + case SHPT_MULTIPOINT: + return "MultiPoint"; + + case SHPT_POINTZ: + return "PointZ"; + + case SHPT_ARCZ: + return "ArcZ"; + + case SHPT_POLYGONZ: + return "PolygonZ"; + + case SHPT_MULTIPOINTZ: + return "MultiPointZ"; + + case SHPT_POINTM: + return "PointM"; + + case SHPT_ARCM: + return "ArcM"; + + case SHPT_POLYGONM: + return "PolygonM"; + + case SHPT_MULTIPOINTM: + return "MultiPointM"; + + case SHPT_MULTIPATCH: + return "MultiPatch"; + + default: + return "UnknownShapeType"; + } +} + +/************************************************************************/ +/* SHPPartTypeName() */ +/************************************************************************/ + +const char SHPAPI_CALL1(*) +SHPPartTypeName( int nPartType ) + +{ + switch( nPartType ) + { + case SHPP_TRISTRIP: + return "TriangleStrip"; + + case SHPP_TRIFAN: + return "TriangleFan"; + + case SHPP_OUTERRING: + return "OuterRing"; + + case SHPP_INNERRING: + return "InnerRing"; + + case SHPP_FIRSTRING: + return "FirstRing"; + + case SHPP_RING: + return "Ring"; + + default: + return "UnknownPartType"; + } +} + +/************************************************************************/ +/* SHPDestroyObject() */ +/************************************************************************/ + +void SHPAPI_CALL +SHPDestroyObject( SHPObject * psShape ) + +{ + if( psShape == NULL ) + return; + + if( psShape->padfX != NULL ) + free( psShape->padfX ); + if( psShape->padfY != NULL ) + free( psShape->padfY ); + if( psShape->padfZ != NULL ) + free( psShape->padfZ ); + if( psShape->padfM != NULL ) + free( psShape->padfM ); + + if( psShape->panPartStart != NULL ) + free( psShape->panPartStart ); + if( psShape->panPartType != NULL ) + free( psShape->panPartType ); + + free( psShape ); +} + +/************************************************************************/ +/* SHPRewindObject() */ +/* */ +/* Reset the winding of polygon objects to adhere to the */ +/* specification. */ +/************************************************************************/ + +int SHPAPI_CALL +SHPRewindObject( SHPHandle hSHP, SHPObject * psObject ) + +{ + int iOpRing, bAltered = 0; + +/* -------------------------------------------------------------------- */ +/* Do nothing if this is not a polygon object. */ +/* -------------------------------------------------------------------- */ + if( psObject->nSHPType != SHPT_POLYGON + && psObject->nSHPType != SHPT_POLYGONZ + && psObject->nSHPType != SHPT_POLYGONM ) + return 0; + +/* -------------------------------------------------------------------- */ +/* Process each of the rings. */ +/* -------------------------------------------------------------------- */ + for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ ) + { + int bInner, iVert, nVertCount, nVertStart, iCheckRing; + double dfSum, dfTestX, dfTestY; + +/* -------------------------------------------------------------------- */ +/* Determine if this ring is an inner ring or an outer ring */ +/* relative to all the other rings. For now we assume the */ +/* first ring is outer and all others are inner, but eventually */ +/* we need to fix this to handle multiple island polygons and */ +/* unordered sets of rings. */ +/* -------------------------------------------------------------------- */ + dfTestX = psObject->padfX[psObject->panPartStart[iOpRing]]; + dfTestY = psObject->padfY[psObject->panPartStart[iOpRing]]; + + bInner = FALSE; + for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ ) + { + int iEdge; + + if( iCheckRing == iOpRing ) + continue; + + nVertStart = psObject->panPartStart[iCheckRing]; + + if( iCheckRing == psObject->nParts-1 ) + nVertCount = psObject->nVertices + - psObject->panPartStart[iCheckRing]; + else + nVertCount = psObject->panPartStart[iCheckRing+1] + - psObject->panPartStart[iCheckRing]; + + for( iEdge = 0; iEdge < nVertCount; iEdge++ ) + { + int iNext; + + if( iEdge < nVertCount-1 ) + iNext = iEdge+1; + else + iNext = 0; + + if( (psObject->padfY[iEdge+nVertStart] < dfTestY + && psObject->padfY[iNext+nVertStart] >= dfTestY) + || (psObject->padfY[iNext+nVertStart] < dfTestY + && psObject->padfY[iEdge+nVertStart] >= dfTestY) ) + { + if( psObject->padfX[iEdge+nVertStart] + + (dfTestY - psObject->padfY[iEdge+nVertStart]) + / (psObject->padfY[iNext+nVertStart] + - psObject->padfY[iEdge+nVertStart]) + * (psObject->padfX[iNext+nVertStart] + - psObject->padfX[iEdge+nVertStart]) < dfTestX ) + bInner = !bInner; + } + } + } + +/* -------------------------------------------------------------------- */ +/* Determine the current order of this ring so we will know if */ +/* it has to be reversed. */ +/* -------------------------------------------------------------------- */ + nVertStart = psObject->panPartStart[iOpRing]; + + if( iOpRing == psObject->nParts-1 ) + nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing]; + else + nVertCount = psObject->panPartStart[iOpRing+1] + - psObject->panPartStart[iOpRing]; + + dfSum = 0.0; + for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ ) + { + dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1] + - psObject->padfY[iVert] * psObject->padfX[iVert+1]; + } + + dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart] + - psObject->padfY[iVert] * psObject->padfX[nVertStart]; + +/* -------------------------------------------------------------------- */ +/* Reverse if necessary. */ +/* -------------------------------------------------------------------- */ + if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) ) + { + int i; + + bAltered++; + for( i = 0; i < nVertCount/2; i++ ) + { + double dfSaved; + + /* Swap X */ + dfSaved = psObject->padfX[nVertStart+i]; + psObject->padfX[nVertStart+i] = + psObject->padfX[nVertStart+nVertCount-i-1]; + psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved; + + /* Swap Y */ + dfSaved = psObject->padfY[nVertStart+i]; + psObject->padfY[nVertStart+i] = + psObject->padfY[nVertStart+nVertCount-i-1]; + psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved; + + /* Swap Z */ + if( psObject->padfZ ) + { + dfSaved = psObject->padfZ[nVertStart+i]; + psObject->padfZ[nVertStart+i] = + psObject->padfZ[nVertStart+nVertCount-i-1]; + psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved; + } + + /* Swap M */ + if( psObject->padfM ) + { + dfSaved = psObject->padfM[nVertStart+i]; + psObject->padfM[nVertStart+i] = + psObject->padfM[nVertStart+nVertCount-i-1]; + psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved; + } + } + } + } + + return bAltered; +} diff --git a/smplrout.c b/smplrout.c new file mode 100644 index 000000000..da2145635 --- /dev/null +++ b/smplrout.c @@ -0,0 +1,251 @@ +/* + Route simplification filter + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include +#include "defs.h" +#include "grtcirc.h" + +#define MYNAME "Route simplification filter" + +static int count = 0; +static char *countopt = NULL; + +static +arglist_t routesimple_args[] = { + {"count", &countopt, "Maximum number of points in route", + NULL, ARGTYPE_INT | ARGTYPE_REQUIRED}, + {0, 0, 0, 0, 0} +}; + +struct xte_intermed; + +struct xte { + double distance; + int ordinal; + struct xte_intermed *intermed; +}; + +struct xte_intermed { + struct xte *xte_rec; + struct xte_intermed *next; + struct xte_intermed *prev; + const waypoint *wpt; +}; + +void +free_xte( struct xte *xte_rec ) +{ + xfree(xte_rec->intermed); +} + +#define HUGEVAL 9e9; + +static struct xte_intermed *tmpprev = NULL; +static int xte_count = 0; +static const route_head *cur_rte = NULL; +static struct xte *xte_recs = NULL; + +void +routesimple_waypt_pr( const waypoint *wpt ) +{ + if ( !cur_rte ) return; + xte_recs[xte_count].ordinal=xte_count; + xte_recs[xte_count].intermed = (struct xte_intermed *) xmalloc( sizeof(struct xte_intermed)); + xte_recs[xte_count].intermed->wpt = wpt; + xte_recs[xte_count].intermed->xte_rec = xte_recs+xte_count; + xte_recs[xte_count].intermed->next = NULL; + xte_recs[xte_count].intermed->prev = tmpprev; + if ( tmpprev ) { + tmpprev->next = xte_recs[xte_count].intermed; + } + tmpprev = xte_recs[xte_count].intermed; + xte_count++; +} + +void +compute_xte( struct xte *xte_rec ) { + const waypoint *wpt3 = xte_rec->intermed->wpt; + const waypoint *wpt1 = NULL; + const waypoint *wpt2 = NULL; + /* if no previous, this is an endpoint and must be preserved. */ + if ( !xte_rec->intermed->prev ) { + xte_rec->distance = HUGEVAL; + return; + } + wpt1 = xte_rec->intermed->prev->wpt; + + /* if no next, this is an endpoint and must be preserved. */ + if ( !xte_rec->intermed->next ) { + xte_rec->distance = HUGEVAL; + return; + } + wpt2 = xte_rec->intermed->next->wpt; + + xte_rec->distance = linedist( + wpt1->latitude, wpt1->longitude, + wpt2->latitude, wpt2->longitude, + wpt3->latitude, wpt3->longitude ); +} + + +int +compare_xte( const void *a, const void *b ) +{ + double distdiff = ((struct xte *)a)->distance - + ((struct xte *)b)->distance; + int priodiff = ((struct xte *)a)->intermed->wpt->route_priority - + ((struct xte *)b)->intermed->wpt->route_priority; + if ( priodiff < 0 ) return 1; + if ( priodiff > 0 ) return -1; + if ( distdiff < 0 ) return 1; + if ( distdiff > 0 ) return -1; + return 0; +} + +void +routesimple_head( const route_head *rte ) +{ + cur_rte = NULL; + /* build array of XTE/wpt xref records */ + xte_count = 0; + tmpprev = NULL; + + /* short-circuit if we already have fewer than the max points */ + if ( count >= rte->rte_waypt_ct) return; + + xte_recs = (struct xte *) xcalloc( rte->rte_waypt_ct, sizeof (struct xte)); + cur_rte = rte; + +} + +void +shuffle_xte( struct xte *xte_rec ) +{ + struct xte tmp_xte; + while ( xte_rec > xte_recs && compare_xte(xte_rec, xte_rec-1) < 0 ) { + tmp_xte.distance = xte_rec->distance; + tmp_xte.ordinal = xte_rec->ordinal; + tmp_xte.intermed = xte_rec->intermed; + xte_rec->distance = xte_rec[-1].distance; + xte_rec->ordinal = xte_rec[-1].ordinal; + xte_rec->intermed = xte_rec[-1].intermed; + xte_rec->intermed->xte_rec = xte_rec; + xte_rec--; + xte_rec->distance = tmp_xte.distance; + xte_rec->ordinal = tmp_xte.ordinal; + xte_rec->intermed = tmp_xte.intermed; + xte_rec->intermed->xte_rec = xte_rec; + } + while ( xte_rec - xte_recs < xte_count-2 && + compare_xte( xte_rec, xte_rec+1) > 0 ) { + tmp_xte.distance = xte_rec->distance; + tmp_xte.ordinal = xte_rec->ordinal; + tmp_xte.intermed = xte_rec->intermed; + xte_rec->distance = xte_rec[1].distance; + xte_rec->ordinal = xte_rec[1].ordinal; + xte_rec->intermed = xte_rec[1].intermed; + xte_rec->intermed->xte_rec = xte_rec; + xte_rec++; + xte_rec->distance = tmp_xte.distance; + xte_rec->ordinal = tmp_xte.ordinal; + xte_rec->intermed = tmp_xte.intermed; + xte_rec->intermed->xte_rec = xte_rec; + } +} + +void +routesimple_tail( const route_head *rte ) +{ + int i; + if ( !cur_rte ) return; + + /* compute all distances */ + for (i = 0; i < xte_count ; i++ ) { + compute_xte( xte_recs+i ); + } + + + /* sort XTE array, lowest XTE last */ + qsort( xte_recs, xte_count, sizeof( struct xte ), compare_xte ); + + for (i = 0; i < xte_count; i++ ) { + xte_recs[i].intermed->xte_rec = xte_recs+i; + } + /* while we still have too many records... */ + while ( count < xte_count ) { + i = xte_count - 1; + /* remove the record with the lowest XTE */ + route_del_wpt( (route_head *)(void *)rte, + (waypoint *)(void *)(xte_recs[i].intermed->wpt)); + + if ( xte_recs[i].intermed->prev ) { + xte_recs[i].intermed->prev->next = xte_recs[i].intermed->next; + compute_xte(xte_recs[i].intermed->prev->xte_rec); + shuffle_xte(xte_recs[i].intermed->prev->xte_rec); + } + if ( xte_recs[i].intermed->next ) { + xte_recs[i].intermed->next->prev = xte_recs[i].intermed->prev; + compute_xte(xte_recs[i].intermed->next->xte_rec); + shuffle_xte(xte_recs[i].intermed->next->xte_rec); + } + xte_count--; + free_xte( xte_recs+xte_count); + /* end of loop */ + } + if ( xte_count ) { + do { + xte_count--; + free_xte( xte_recs+xte_count ); + } while(xte_count); + } + xfree( xte_recs ); +} + +void +routesimple_process( void ) +{ + route_disp_all( routesimple_head, routesimple_tail, routesimple_waypt_pr ); + track_disp_all( routesimple_head, routesimple_tail, routesimple_waypt_pr ); +} + +void +routesimple_init(const char *args) { + count = 0; + + if (countopt) { + count = atol(countopt); + } + else { + fatal( MYNAME ": You must specify a maximum size for the new route"); + } +} + +void +routesimple_deinit(void) { + /* do nothing */ +} + +filter_vecs_t routesimple_vecs = { + routesimple_init, + routesimple_process, + routesimple_deinit, + NULL, + routesimple_args +}; diff --git a/sort.c b/sort.c new file mode 100644 index 000000000..e91af8317 --- /dev/null +++ b/sort.c @@ -0,0 +1,108 @@ +/* + Arbitrary Sorting Filter(s) + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include "defs.h" + +extern queue waypt_head; + +typedef enum { + sm_unknown = 0, + sm_gcid, + sm_shortname, + sm_description +} sort_mode_; + +sort_mode_ sort_mode = sm_shortname; /* How are we sorting these? */ + +static char *opt_sm_gcid, *opt_sm_shortname, *opt_sm_description; + +static +arglist_t sort_args[] = { + {"gcid", &opt_sm_gcid, "Sort by numeric geocache ID", + NULL, ARGTYPE_BOOL }, + {"shortname", &opt_sm_shortname, "Sort by waypoint short name", + NULL, ARGTYPE_BOOL }, + {"description", &opt_sm_description, "Sort by waypoint description", + NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + +static int +sort_comp(const void * a, const void * b) +{ + const waypoint *x1 = *(waypoint **)a; + const waypoint *x2 = *(waypoint **)b; + + switch (sort_mode) { + case sm_gcid: return x1->gc_data.id > x2->gc_data.id; + case sm_shortname: return strcmp (x1->shortname, x2->shortname); + case sm_description: return strcmp (x1->description, x2->description); + default: abort(); /* Internal caller error. */ + } +} + +void +sort_process(void) +{ + queue * elem, * tmp; + waypoint ** comp; + int i = 0, wc; + + wc = waypt_count(); + + comp = (waypoint **) xcalloc(wc, sizeof(*comp)); + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + comp[i] = (waypoint *)elem; + waypt_del(comp[i]); /* Pop this waypoint off the master Q */ + i++; + } + + qsort(comp, wc, sizeof(waypoint *), sort_comp); + + /* + * Now re-add the list back. + */ + for (i = 0; i < wc ; i++) { + waypt_add(comp[i]); + } + + if (comp) + xfree(comp); +} + +void +sort_init(const char *args) +{ + if (opt_sm_gcid) + sort_mode = sm_gcid; + if (opt_sm_shortname) + sort_mode = sm_shortname; + if (opt_sm_description) + sort_mode = sm_description; +} + +filter_vecs_t sort_vecs = { + sort_init, + sort_process, + NULL, + NULL, + sort_args +}; diff --git a/stackfilter.c b/stackfilter.c new file mode 100644 index 000000000..d9a82d98a --- /dev/null +++ b/stackfilter.c @@ -0,0 +1,192 @@ +/* + Stack filter + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include +#include "defs.h" + +#define MYNAME "Stack filter" + +extern queue waypt_head; + +static char *opt_push = NULL; +static char *opt_copy = NULL; +static char *opt_pop = NULL; +static char *opt_append = NULL; +static char *opt_discard = NULL; +static char *opt_replace = NULL; +static char *opt_swap = NULL; +static char *opt_depth = NULL; +static char *nowarn = NULL; +static int warnings_enabled = 1; +static int swapdepth = 0; + +static +arglist_t stackfilt_args[] = { + {"push", &opt_push, "Push waypoint list onto stack", NULL, + ARGTYPE_BOOL}, + {"copy", &opt_copy, "Copy waypoint list when pushing", NULL, + ARGTYPE_BOOL}, + {"pop", &opt_pop, "Pop waypoint list from stack", NULL, + ARGTYPE_BOOL}, + {"append", &opt_append, "Append list when popping", NULL, + ARGTYPE_BOOL}, + {"discard", &opt_discard, "Discard top of stack when popping", + NULL, ARGTYPE_BOOL}, + {"replace", &opt_replace, "Replace list with top of stack (default)", + NULL, ARGTYPE_BOOL}, + {"swap", &opt_swap, "Swap waypoint list with item on stack", + NULL, ARGTYPE_BOOL}, + {"depth", &opt_depth, "Item to use when swapping", NULL, ARGTYPE_INT}, + {"nowarn", &nowarn, "Suppress cleanup warning", NULL, + ARGTYPE_INT | ARGTYPE_HIDDEN}, + {0, 0, 0, 0, 0} +}; + +struct stack_elt { + queue waypts; + struct stack_elt *next; +} *stack = NULL; + + +void +stackfilt_process(void) +{ + struct stack_elt *tmp_elt = NULL; + queue *elem = NULL; + queue *tmp = NULL; + queue tmp_queue; + waypoint *wpt_tmp; + + if ( opt_push ) { + tmp_elt = (struct stack_elt *)xmalloc(sizeof(struct stack_elt)); + QUEUE_MOVE(&(tmp_elt->waypts), &waypt_head); + tmp_elt->next = stack; + stack = tmp_elt; + if ( opt_copy ) { + QUEUE_FOR_EACH( &(stack->waypts), elem, tmp ) { + waypt_add( waypt_dupe((waypoint *)elem)); + } + } + } + else if ( opt_pop ) { + tmp_elt = stack; + if ( !tmp_elt ) { + fatal( MYNAME ": stack empty\n"); + } + if ( opt_append ) { + QUEUE_FOR_EACH( &(stack->waypts), elem, tmp ) { + waypt_add( (waypoint *)elem); + } + } + else if ( opt_discard ) { + waypt_flush( &(stack->waypts) ); + } + else { + waypt_flush( &waypt_head ); + QUEUE_MOVE(&(waypt_head), &(stack->waypts) ); + } + stack = tmp_elt->next; + xfree( tmp_elt ); + } + else if ( opt_swap ) { + tmp_elt = stack; + while ( swapdepth > 1 ) { + if ( !tmp_elt->next ) { + fatal (MYNAME ": swap with nonexistent element\n"); + } + tmp_elt = tmp_elt->next; + swapdepth--; + } + QUEUE_MOVE(&tmp_queue, &(tmp_elt->waypts) ); + QUEUE_MOVE(&(tmp_elt->waypts), &waypt_head ); + QUEUE_MOVE(&waypt_head, &tmp_queue ); + } +} + +void +stackfilt_init(const char *args) { + + int invalid = 0; + + if ( nowarn ) { + warnings_enabled = 0; + } + + if ( opt_depth ) { + swapdepth = atoi( opt_depth ); + } + if ( opt_push ) { + if ( opt_pop || opt_append || opt_discard || opt_replace || + opt_swap || opt_depth ) { + invalid = 1; + } + } + else if ( opt_pop ) { + if ( opt_push || opt_copy || opt_swap || opt_depth ) { + invalid = 1; + } + if ( !!opt_append + !!opt_discard + !!opt_replace > 1 ) { + invalid = 1; + } + } + else if ( opt_swap ) { + if ( opt_push || opt_copy || opt_pop || opt_append || + opt_discard || opt_replace ) { + invalid = 1; + } + } + else { + invalid = 1; + } + + if ( invalid ) { + fatal (MYNAME ": invalid combination of options\n"); + } + +} + +void +stackfilt_deinit(void) { + swapdepth = 0; +} + +void +stackfilt_exit( void ) { + struct stack_elt *tmp_elt = NULL; + + if ( warnings_enabled && stack ) { + warning( MYNAME " Warning: leftover stack entries; " + "check command line for mistakes\n" ); + } + while ( stack ) { + waypt_flush( &(stack->waypts) ); + tmp_elt = stack; + stack = stack->next; + xfree(tmp_elt); + } +} + +filter_vecs_t stackfilt_vecs = { + stackfilt_init, + stackfilt_process, + stackfilt_deinit, + stackfilt_exit, + stackfilt_args +}; diff --git a/style/README.style b/style/README.style new file mode 100644 index 000000000..c5737f5b5 --- /dev/null +++ b/style/README.style @@ -0,0 +1,397 @@ +GPSBabel XCSV Style File Layout: + +The format of an XCSV style file is quite simple and designed to be easily +implemented by non-programmers to handle "one-off" babel-ization of various +XCSV (whatever separated values) text files. The format and usage of the +various style directives are described below. + +The first and foremost important step is understanding how the config +file is laid out itself. The format is: + +DIRECTIVEVALUE + +Where is a space, tab, spaces, tabs, etc... There should +be *nothing* before the directive. (i.e. not " DIRECTIVE VALUE") + +INTERNAL CONSTANTS: +A few internal constants are defined in the XCSV parser to make the style +file simpler. They may or may not be used and are optional in most cases. +Note that only certain style file directives map these constants. + +STYLE CONSTANT MAPS TO CHAR(s) +--------------------------------------- +COMMA , +COMMASPACE , +SINGLEQUOTE ' +DOUBLEQUOTE " +COLON : +SEMICOLON ; +NEWLINE \n +CR \r +CRNEWLINE \r\n +TAB \t +SPACE +HASH # +WHITESPACE *** SEE WHITESPACE NOTES BELOW *** + +WHITESPACE: +The WHITESPACE constant has special properties. When reading data, +WHITESPACE refers to sequential runs of SPACES and/or TABS. When +writing data, WHITESPACE is always a single SPACE. + +For example, the following line: +SOME_NAME 30.1208 -91.1365 SOME OTHER NAME + +Parses into the following data fields: +SOME_NAME,30.1208,-91.1365,SOME,OTHER,NAME + + +COMMENTS: +Anything after a hash (#) on a line is not parsed. For example: +#THIS ENTIRE LINE IS A COMMENT. +#FIELD LAT_DECIMAL, "", "%f" THIS ENTIRE LINE IS A COMMENT +FIELD LAT_DECIMAL, "", "%f" # ONLY THIS SENTENCE IS A COMMENT. + + + +GLOBAL PROPERTIES OF THE FILE: +-------------------------------- +There are a few available directives to describe general traits of the +file being described and not specific data within the file itself. + + o DESCRIPTION: + + This is the description of the file format being described. This text + appears in the help screens and in menus used by the various GUI wrappers. + + o EXTENSION: + + This directive gives the filename extension generally associated with + this file. + +GPSBABEL BEHAVIOR DIRECTIVES: +----------------------------- +There are a few available directives to 'control' some of the internal +processing functions of GPSbabel. + + o SHORTLEN: + + This sets the maximum allowed shortname length when using the internal + shortname synthesizer. + + example: + SHORTLEN 16 # shortnames will be at most 16 characters long. + + + o SHORTWHITE: + + This tells the shortname synthesizer whether or not to allow whitespace + in the synthesized shortnames. Allowed values are zero and one. + + example: + SHORTWHITE 0 # Do not allow whitespace in shortname. + SHORTWHITE 1 # Allow whitespace in shortname. + + +DEFINING THE LAYOUT OF THE FILE: +-------------------------------- +The first few directives define the layout the physical file itself: + + o FIELD_DELIMITER: + The field delimiter defines the character(s) that separate the fields in + the rows of data inside the XCSV file. Common field delimiters are commas + and tabs. (referred to as "comma separated values" and "tab separated + values") + + examples: FIELD_DELIMITER COMMA + FIELD_DELIMITER ~ + + The directive FIELD_DELIMITER is parsed for STYLE CONSTANTS as defined in + the table above. + + o RECORD DELIMITER: + The record delimiter defines that character(s) that separate ROWS of + data (FIELDS) in the XCSV file. The most common record delimiters + are NEWLINE and CR (carriage return). + + example: RECORD_DELIMITER NEWLINE + RECORD_DELIMITER | + + The directive RECORD_DELIMITER is parsed for STYLE CONSTANTS as defined + in the table above. + + o BADCHARS: + Bad characters are things that should *never* be written into the XCSV + file as data on output. GPSBabel automatically includes any non-blank + FIELD_DELIMITER and RECORD_DELIMITER characters as BADCHARS by default. + + example: BADCHARS COMMA + BADCHARS ~| + + The directive BADCHARS is parsed for STYLE CONSTANTS as defined in the + table above. + + o PROLOGUE + A prologue is basically constant data that is written to the output + file BEFORE any waypoints are processed. PROLOGUE can be defined + multiple times in the style file, once for each "line" before the data + begins. This is commonly used in XCSV files as a "header" row. + + example: PROLOGUE OziExplorer Waypoint File Version 1.1 + PROLOGUE WGS 84 + * or * + PROLOGUE Symbol,Name,Latitude,Longitude + + o EPILOGUE + An Epilogue is the same as a prologue, except this data is written at + the END of the file. See the examples for PROLOGUE above. + + +DEFINING FIELDS WITHIN THE FILE: +------------------------------- + +A field defines data. There are two different classifications of FIELDS, +IFIELD (file input) and OFIELD (file output). In the absence of any OFIELDS, +IFIELDS are use as both input and output. The existence of OFIELDS is +primarily to allow more flexible mapping of GPSBabel data to output data +(say, for instance, to map the internal GPSBabel "description" variable to +two or more fields on output). For all practical purposes, IFIELDS and +OFIELDS are defined the same way in the style file. + +There are several different types of fields that may be defined. Each field +consists of three pieces of information: the FIELD TYPE, a DEFAULT VALUE, and +a PRINTF CONVERSION (for output). In many cases, not all pieces are used, +but all 3 pieces are required. + +FIELDS should be defined in the style file in the logical order that they +appear in the data, from left to right. This is the order in which they are +parsed from input and written to output. + +The fields used by the XCSV parser are as follows: + + o IGNORE + IGNORE fields are, guess what, ignored on input. Internally, IGNORE + fields are treated as CHARACTER data, and as such, require a printf + conversion for a character array. + + example: IFIELD IGNORE,"","%14.14s" (writes a 14 character blank field) + IFIELD IGNORE,"","%s" (writes a blank field on output) + + o CONSTANT + CONSTANT fields are, of course, constant. They are ignored on input, + however they write CONSTANT data on output. As such, they require a + DEFAULT VALUE and a printf conversion for a character array. + + example: IFIELD CONSTANT,"FFFFFF","%s" (writes "FFFFFF" in the field) + IFIELD CONSTANT,"01/01/70","%s" (a constant date field) + + o INDEX + An INDEX field is used ONLY on output. The INDEX constant defines a field + that, at output, contains the sequence number of the waypoint being + written, starting at 0. An index is managed internally as an INTEGER + and requires an INTEGER printf conversion. An INDEX has one special + property. The DEFAULT VALUE of the index is added to the index + on each iteration (to allow indexes starting at 1, 100, etc..). + + example: IFIELD INDEX,"0","%04d" (Starts counting at zero) + IFIELD INDEX,"","%04d" (Starts counting at zero) + IFIELD INDEX,"1","%04d" (Starts counting at one) + + o SHORTNAME + A SHORTNAME is generally the waypoint name of the data being processed. + SHORTNAME maps directly to the GPSBabel variable ->shortname. A SHORTNAME + is CHARACTER data and requires a character array printf conversion. + + example: IFIELD SHORTNAME,"","%s" (write shortname in the output file) + + o DESCRIPTION + A DESCRIPTION is generally a long description of the waypoint. A + DESCRIPTION maps to the GPSBabel variable ->description and is otherwise + handled exactly like a SHORTNAME. + + example: IFIELD DESCRIPTION,"","%s" (write description in the output file) + + o NOTES + NOTES are generally everything else about a waypoints. NOTES map to the + GPSBabel variable ->notes and is otherwise handled exactly like a + SHORTNAME. + + o URL + URL is a URL for the waypoint. URL maps to the GPSBabel variable + ->url and is otherwise handled exactly like a SHORTNAME. + + example: IFIELD URL,"","%s" (writes the URL in the output file) + + o URL_LINK_TEXT + URL_LINK_TEXT is a textual description of where a URL points. + URL_LINK_TEXT maps to the GPSBabel variable ->url_link_text and + is otherwise handled exactly like a SHORTNAME. + + example: IFIELD URL_LINK_TEXT,"","%s" (writes link text in the output file) + + o ICON_DESCR + ICON_DESCR is a textual description of an icon type for a waypoint. + ICON_DESCR maps to the GPSBabel variable ->icon_desc and is otherwise + handled exactly like a SHORTNAME. + + example: IFIELD ICON_DESCR,"","%s" (writes link text in the output file) + + o LAT_DECIMAL + LAT_DECIMAL defines LATITUDE in DECIMAL format. Note that this is a PURE + signed decimal format (i.e. -91.0000). This data is handled internally as + a DOUBLE PRECISION FLOAT and requires a FLOATING POINT printf conversion. + + example: IFIELD LAT_DECIMAL,"","%f" + + o LON_DECIMAL + See LAT_DECIMAL, except LON_DECIMAL defines LONGITUDE. + + o LAT_INT32DEG + LAT_INT32DEG defines LATITUDE in what I call INT32DEGREES. This value is + a signed LONG INTEGER and requires a LONG INTEGER printf conversion. + + example: IFIELD LAT_INT32DEG,"","%ld" + + o LON_INT32DEG + See LON_INT32DEG except LON_INT32DEG defines LONGITUDE. + + o LAT_DECIMALDIR / LAT_DIRDECIMAL + LAT_DECIMALDIR and LAT_DIRDECIMAL defines LATITUDE in DECIMAL format + with the added bonus of a 'N/S' or 'E/W' direction character. This data + is handled internally as a DOUBLE PRECISION FLOAT and a single + CHARACTER and requires a FLOATING POINT as well as a CHARACTER printf + conversion. The only difference between the two is whether the directional + character appears before (LAT_DIRDECIMAL) or after (LAT_DECIMALDIR) the + decimal number. + + example: IFIELD LAT_DECIMALDIR,"","%f %c" (writes 31.333 N) + example: IFIELD LAT_DIRDECIMAL,"","%c %f" (writes N 31.333) + + o LON_DECIMALDIR / LON_DIRDECIMAL + Same as LAT_DECIMALDIR / LAT_DIRDECIMAL except LON_ defines LONGITUDE. + + o LAT_DIR / LON_DIR + LAT_DIR returns the single character 'N' or 'S' depending on the + hemisphere of the latitude. LON_DIR returns 'E' or 'W' depending on + the hemisphere of the longitude. + + o LAT_HUMAN_READABLE + LAT_HUMAN_READABLE defines LATITUDE in a human-readable format. This + format is probably the most expressive format. It is similar to + LAT_DECIMALDIR in that it requires multiple printf conversions, but it + is far more flexible as to the contents of those conversions. On read, + the printf conversions are ignored and GPSBabel attempts to determine the + latitude and longitude based on what is in the file. + + example: IFIELD LAT_HUMAN_READABLE,"","%c %d %f" (writes N 31 40.000) + example: IFIELD LAT_HUMAN_READABLE,"","%d deg %f min %c" + (writes "31 deg 40.000 min N") + Note that this string will confuse the reading routine due + to the letter "n" in "min" and the letter "e" in "deg." + example: IFIELD LAT_HUMAN_READABLE,"","%d %d %f%c" (writes 31 40 00.000N) + + o LAT_NMEA + Defines the latitude in the format used by the NMEA standard which is + degrees multiplied by 100 plus decimal minutes. + + example: IFIELD LAT_NMEA, "%f", "%08.3f" (writes 3558.322) + + o LON_NMEA + Defines the longitude in the format used by the NMEA standard which is + degrees multiplied by 100 plus decimal minutes. + + example: IFIELD LON_NMEA, "%f", "%010.3f" (writes -08708.082) + + o LON_HUMAN_READABLE + See LAT_HUMAN_READABLE except LON_HUMAN_READABLE defines LONGITUDE. + + o LATLON_HUMAN_READABLE + LATLON_HUMAN_READABLE is like LAT_HUMAN_READABLE and LON_HUMAN_READABLE + except that it reads and writes both latitude and longitude as a single + field. On write, the same format specifier is used for both coordinates. + On read, GPSBabel does exactly the same thing it does for + LAT_HUMAN_READABLE or LON_HUMAN_READABLE. + + example: IFIELD LATLON_HUMAN_READABLE,"","%c %d %f" + (writes "N 31 40.126 W 85 09.62" as a single field) + + o ALT_FEET + ALT_FEET is the position's ALTITUDE in FEET. This value is treated as + a SIGNED DOUBLE PRECISION FLOAT and requires a FLOATING POINT printf + conversion. + + example: IFIELD ALT_FEET,"","%.0f" + + o ALT_METERS + ALT_METERS is identical to ALT_FEET with the exception that the altitude + is in METERS. + + o EXCEL_TIME + EXCEL_TIME is the waypoint's creation time, if any. This is actually + the decimal days since 1/1/1900 and is handled internally as a DOUBLE + PRECISION FLOAT and requires a FLOATING POINT printf conversion. + + example: IFIELD EXCEL_TIME,"","%11.5f" + + o TIMET_TIME + TIMET_TIME is the waypoint's creation time, if any. This is actually + the integer seconds since 1/1/1970 (let's not start the holy war) and + is handled internally as a LONG INTEGER and requires a LONG INTEGER + printf conversion. + + example: IFIELD TIMET_TIME,"","%ld" + + o GEOCACHE_DIFF + GEOCACHE_DIFF is valid only for geocaches and represents a DOUBLE + PRECISION FLOAT. A "three and a half star" cache would therefore be "3.5" + + example: IFIELD GEOCACHE_DIFF,"","%3.1f" + + o GEOCACHE_TERR + GEOCACHE_TERR is valid only for geocaches and represents a DOUBLE + PRECISION FLOAT. A "three and a half star" cache would therefore be "3.5" + + example: IFIELD GEOCACHE_TERR,"","%3.1f" + + o GEOCACHE_CONTAINER + GEOCACHE_CONTAINER is valid only for geocaches and is heavily influenced + by the Groundspeak container types. Examples would include "Micro" + and "Virtual". + + example: GEOCACHE_CONTAINER,"","%s" + + o GEOCACHE_TYPE + GEOCACHE_TYPE is valid only for geocaches and is heavily influenced + by the Groundspeak cache types. Examples would include "Event cache" + and "Multi-Cache". + + example: GEOCACHE_TYPE,"","%s" + + o PATH_DISTANCE_MILES + PATH_DISTANCE_MILES outputs the total length of the route or track from + the start point to the current point, in miles. This and the altitude + could be used to create an elevation profile. PATH_DISTANCE_MILES is + a DOUBLE PRECISION FLOAT. + PATH_DISTANCE_MILES is not valid as an input field. + PATH_DISTANCE_MILES is only meaningful if the data comes from a track + or a route; waypoint data will generate essentially meaningless output. + + example: PATH_DISTANCE_MILES,"","%f" + + o PATH_DISTANCE_KM + PATH_DISTANCE_KM is like PATH_DISTANCE_MILES except it outputs the + length in kilometers. + +EXAMPLES: +-------- +For examples on using the XCSV module, please see the *.style files in +the style/ subdirectory of GPSBabel. + +MISCELLANEOUS NOTES: +-------------------- + o DEFAULT VALUES + Default values are supported for any output fields that contain pure + character data output such as URL and NOTES. Default values are only + written on output and are not used to supplement missing input. When + using default values your mileage will vary greatly depending on the + input formats used to populate waypoint data. diff --git a/style/arc.style b/style/arc.style new file mode 100644 index 000000000..82fcbc9bc --- /dev/null +++ b/style/arc.style @@ -0,0 +1,21 @@ +# gpsbabel XCSV style file +# +# Format: GPSBabel arc filter format +# Author: Ron Parker +# Date: 17 July 2003 +# + +DESCRIPTION GPSBabel arc filter file +EXTENSION txt + +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER TAB +RECORD_DELIMITER NEWLINE + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD LAT_DECIMAL, "", "%08.5f" +IFIELD LON_DECIMAL, "", "%08.5f" diff --git a/style/csv.style b/style/csv.style new file mode 100644 index 000000000..372634acb --- /dev/null +++ b/style/csv.style @@ -0,0 +1,23 @@ +# gpsbabel XCSV style file +# +# Format: Delorme SA 9.0 CSV +# Author: Alex Mottram +# Date: 12/09/2002 +# +# +DESCRIPTION Comma separated values +SHORTLEN 8 +# +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER COMMASPACE +RECORD_DELIMITER NEWLINE +BADCHARS COMMA + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD LAT_DECIMAL, "", "%08.5f" +IFIELD LON_DECIMAL, "", "%08.5f" +IFIELD DESCRIPTION, "", "%s" diff --git a/style/custom.style b/style/custom.style new file mode 100644 index 000000000..d3776aaf1 --- /dev/null +++ b/style/custom.style @@ -0,0 +1,52 @@ +# gpsbabel XCSV style file +# +# Format: Custom "Everything" Style +# Author: Alex Mottram +# Date: 11/24/2002 +# +# + +DESCRIPTION Custom "Everything" Style + +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER COMMA +RECORD_DELIMITER NEWLINE +BADCHARS COMMA +FORMAT_TYPE INTERNAL + +# +# HEADER STUFF: +# +PROLOGUE Prologue Line 1 __FILE__ +PROLOGUE Prologue Line 2 + +# +# INDIVIDUAL DATA FIELDS: +# +IFIELD CONSTANT, "", "CONSTANT" +IFIELD INDEX, "", "%d" +IFIELD LAT_DECIMAL, "", "%f" +IFIELD LAT_DIR, "", "%c" +IFIELD LON_DECIMAL, "", "%f" +IFIELD LON_DIR, "", "%c" +IFIELD ICON_DESCR, "", "%s" +IFIELD SHORTNAME, "", "%s" +IFIELD DESCRIPTION, "", "%s" +IFIELD NOTES, "", "%s" +IFIELD URL, "", "%s" +IFIELD URL_LINK_TEXT, "", "%s" +IFIELD ALT_METERS, "", "%fM" +IFIELD ALT_FEET, "", "%fF" +IFIELD LAT_DECIMALDIR, "", "%f/%c" +IFIELD LON_DECIMALDIR, "", "%f/%c" +IFIELD LAT_DIRDECIMAL, "", "%c/%f" +IFIELD LON_DIRDECIMAL, "", "%c/%f" +IFIELD LAT_INT32DEG, "", "%ld" +IFIELD LON_INT32DEG, "", "%ld" +IFIELD TIMET_TIME, "", "%ld" +IFIELD EXCEL_TIME, "", "%f" + +# EPILOGUE: +EPILOGUE Epilogue Line 1 +EPILOGUE Epilogue Line 2 diff --git a/style/dna.style b/style/dna.style new file mode 100644 index 000000000..5cbacbec8 --- /dev/null +++ b/style/dna.style @@ -0,0 +1,28 @@ +# gpsbabel XCSV style file +# +# Format: DNA Marker Format +# Author: Alex Mottram +# Date: 12/09/2002 +# +# +# As defined in dna.c +# +# + +DESCRIPTION Navitrak DNA marker format +EXTENSION dna + +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER COMMA +RECORD_DELIMITER NEWLINE +BADCHARS COMMA + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD INDEX, "", "%d" +IFIELD LAT_DECIMAL, "", "%08.5f" +IFIELD LON_DECIMAL, "", "%08.5f" +IFIELD DESCRIPTION, "", "%s" + diff --git a/style/fugawi.style b/style/fugawi.style new file mode 100644 index 000000000..9a03c35fa --- /dev/null +++ b/style/fugawi.style @@ -0,0 +1,39 @@ +# fugawi XCSV style file +# +# Format: Fugawi +# Author: Robert Lipe +# Date: 03/10/2003 +# +# + +DESCRIPTION Fugawi +EXTENSION txt +SHORTLEN 10 + +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER COMMA +RECORD_DELIMITER NEWLINE +BADCHARS COMMA + +PROLOGUE \# Latitude, Longitude and UTM coordinates are in WGS84 datum +PROLOGUE \# +PROLOGUE \# Every set of data contains the following: +PROLOGUE \# +PROLOGUE \# Waypoint name +PROLOGUE \# Waypoint comment +PROLOGUE \# Waypoint description +PROLOGUE \# Latitude in Degree and decimals (soutern hemisphere has neg. degrees) +PROLOGUE \# Longitude in degree and decimals (neg. numbers: west of Greenwich) +PROLOGUE \# Height in meters + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD SHORTNAME, "", "%s" +IFIELD DESCRIPTION, "", "%s" +IFIELD NOTES, "", "%s" +IFIELD LAT_DECIMAL, "", "%-.7f" +IFIELD LON_DECIMAL, "", "%-.7f" +IFIELD ALT_METERS, "", "%-7.1f" diff --git a/style/gpsdrive.style b/style/gpsdrive.style new file mode 100644 index 000000000..dfe80ccaa --- /dev/null +++ b/style/gpsdrive.style @@ -0,0 +1,32 @@ +# gpsbabel XCSV style file +# +# Format: GPSDrive +# Author: Alex Mottram +# Date: 12/11/2002 +# +# +# + +DESCRIPTION GpsDrive Format + +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER WHITESPACE +RECORD_DELIMITER NEWLINE +BADCHARS ,'" + +SHORTLEN 20 +SHORTWHITE 0 + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: + +IFIELD SHORTNAME, "", "%s" +IFIELD LAT_DECIMAL, "", "%08.5f" +IFIELD LON_DECIMAL, "", "%08.5f" +IFIELD ICON_DESCR, "", "%s" + +OFIELD ANYNAME, "", "%s" +OFIELD LAT_DECIMAL, "", "%08.5f" +OFIELD LON_DECIMAL, "", "%08.5f" +OFIELD ICON_DESCR, "", "%s" diff --git a/style/gpsman.style b/style/gpsman.style new file mode 100644 index 000000000..e1046dcce --- /dev/null +++ b/style/gpsman.style @@ -0,0 +1,34 @@ +# gpsbabel XCSV style file +# +# Format: GPSMAN Format +# Author: Alex Mottram +# Date: 12/09/2002 +# +# +# As defined in gpsman.c +# +# + +DESCRIPTION GPSman +SHORTLEN 8 +SHORTWHITE 0 + +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER TAB +RECORD_DELIMITER NEWLINE +BADCHARS TAB + +PROLOGUE !Format: DDD 1 WGS 84 +PROLOGUE !W: + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD SHORTNAME, "", "%-8.8s" +IFIELD DESCRIPTION, "", "%s" +IFIELD LAT_DIRDECIMAL, "", "%c%f" +IFIELD LON_DIRDECIMAL, "", "%c%f" +IFIELD IGNORE, "", "%s" + +# gpsman.c likes mkshort len = 8, whitespace = 0. diff --git a/style/mapconverter.style b/style/mapconverter.style new file mode 100644 index 000000000..cf38b1f15 --- /dev/null +++ b/style/mapconverter.style @@ -0,0 +1,35 @@ +# Format: Mapopolis.com Mapconverter +# Author: Gary Paulson +# Date: 01/13/2003 +# Requires unsupported mapconverter.exe from mapopolis.com. +# +# Modifications by Alex Mottram documented 6/30/2003 +# Change %-40.40s on description output to %-.40s to stop padding. +# Add QUOTE as badchars, remove COMMA. +# Removed Mapconverter.exe's README information from style file. +# Changed OFIELD to IFIELD in case you ever want to read one of these things. +# +# +DESCRIPTION Mapopolis.com Mapconverter CSV +EXTENSION txt + +# FILE LAYOUT DEFINITIIONS: + +FIELD_DELIMITER COMMASPACE +RECORD_DELIMITER NEWLINE +BADCHARS ", + +# Map Info Record (header): +PROLOGUE M, "Geocaches", "GPSBabel", Geocaches, __FILE__ +# + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +# L Records: +IFIELD CONSTANT, "L", "%s" # [L]ANDMARK +IFIELD CONSTANT, "Geocaches", "%s" # Category for Landmark Searches +IFIELD DESCRIPTION, "", "%-.40s" # Name +IFIELD CONSTANT, "1", "%s" # View at Zoom Level 1 (1-4) +IFIELD LON_DECIMAL, "", "%08.5f" # Longitude +IFIELD LAT_DECIMAL, "", "%08.5f" # Latitude diff --git a/style/mxf.style b/style/mxf.style new file mode 100644 index 000000000..e0229b792 --- /dev/null +++ b/style/mxf.style @@ -0,0 +1,39 @@ +# gpsbabel XCSV style file +# +# Format: Ozi Explorer +# Author: Alex Mottram +# Date: 12/09/2002 +# +# +# As used in mxf.c +# +# + +DESCRIPTION MapTech Exchange Format +EXTENSION mxf + +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER COMMASPACE +RECORD_DELIMITER NEWLINE +BADCHARS ", + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD LAT_DECIMAL, "", "%08.5f" +IFIELD LON_DECIMAL, "", "%08.5f" +IFIELD DESCRIPTION, "", "%s" +IFIELD SHORTNAME, "", "%s" +IFIELD IGNORE, "", "%s" +IFIELD CONSTANT, "ff0000", "%s" # COLOR +IFIELD CONSTANT, "47", "%s" # ICON + +OFIELD LAT_DECIMAL, "", "%08.5f" +OFIELD LON_DECIMAL, "", "%08.5f" +OFIELD DESCRIPTION, "", ""%s"" +OFIELD SHORTNAME, "", ""%s"" +OFIELD DESCRIPTION, "", ""%s"" +OFIELD CONSTANT, "ff0000", "%s" # COLOR +OFIELD CONSTANT, "47", "%s" # ICON diff --git a/style/nima.style b/style/nima.style new file mode 100644 index 000000000..f0562db59 --- /dev/null +++ b/style/nima.style @@ -0,0 +1,45 @@ +# gpsbabel XCSV style file +# +# Format: NIMA/GNIS Geographic Names File +# Author: Alex Mottram +# Date: 11/24/2002 +# + +DESCRIPTION NIMA/GNIS Geographic Names File + +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER TAB +RECORD_DELIMITER NEWLINE +BADCHARS TAB +PROLOGUE RC UFI UNI DD_LAT DD_LONG DMS_LAT DMS_LONG UTM JOG FC DSG PC CC1 ADM1 ADM2 DIM CC2 NT LC SHORT_FORM GENERIC SORT_NAME FULL_NAME FULL_NAME_ND MODIFY_DATE + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD IGNORE, "", "%s" # RC +IFIELD IGNORE, "", "%s" # UFI +IFIELD IGNORE, "", "%s" # UNI +IFIELD LAT_DECIMAL, "", "%f" # DD_LAT +IFIELD LON_DECIMAL, "", "%f" # DD_LON +IFIELD IGNORE, "", "%s" # DMS_LAT +IFIELD IGNORE, "", "%s" # DMS_LON +IFIELD IGNORE, "", "%s" # UTM +IFIELD IGNORE, "", "%s" # JOG +IFIELD IGNORE, "", "%s" # FC +IFIELD IGNORE, "", "%s" # DSG +IFIELD IGNORE, "", "%s" # PC +IFIELD IGNORE, "", "%s" # CC1 +IFIELD IGNORE, "", "%s" # ADM1 +IFIELD IGNORE, "", "%s" # ADM2 +IFIELD IGNORE, "", "%s" # DIM +IFIELD IGNORE, "", "%s" # CC2 +IFIELD IGNORE, "", "%s" # NT +IFIELD IGNORE, "", "%s" # LC +IFIELD IGNORE, "", "%s" # SHORT_FORM +IFIELD IGNORE, "", "%s" # GENERIC +IFIELD SHORTNAME, "", "%s" # SORT_NAME +IFIELD IGNORE, "", "%s" # FULL_NAME (unicoded!) +IFIELD DESCRIPTION, "", "%s" # FULL_NAME_ND +IFIELD IGNORE, "", "%s" # MODIFY_DATE diff --git a/style/s_and_t.style b/style/s_and_t.style new file mode 100644 index 000000000..60da4b4ee --- /dev/null +++ b/style/s_and_t.style @@ -0,0 +1,36 @@ +# gpsbabel XCSV style file +# +# Format: MS S&T 2002/2003 +# Author: Alex Mottram +# Date: 12/09/2002 +# +# +# As requested by Noel Shrum on the gpsbabel-code mailing list. +# Name,Latitude,Longitude,Name 2,URL,Type +# GCCBF,44.479133,-85.56515,High Rollaway by rjlint,http://www.geocaching.com/seek/cache_details.aspx?ID=3263,Traditional Cache +# GC110D,44.6522,-85.492483,Brown Bridge Pond Peek-a-Boo Cache by Big Bird,http://www.geocaching.com/seek/cache_details.aspx?ID=4365,Traditional Cache +# GC171C,44.70605,-85.62265,The Michigan Frog by RealDcoy & LRB,http://www.geocaching.com/seek/cache_details.aspx?ID=5916,Traditional Cache +# + +DESCRIPTION Microsoft Streets and Trips 2002/2003 + +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER COMMA +RECORD_DELIMITER NEWLINE +BADCHARS ," + +PROLOGUE Name,Latitude,Longitude,Name 2,URL,Type + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# NOTE: MS S&T ONLY IMPORTS DATA, IT DOESN'T EXPORT THIS ANYWHERE SO WE CAN +# HAVE OUR WAY WITH THE FORMATTING. +# +IFIELD SHORTNAME, "", "%s" # Name +IFIELD LAT_DECIMAL, "", "%f" # Latitude +IFIELD LON_DECIMAL, "", "%f" # Longitude +IFIELD DESCRIPTION, "", "%s" # Name 2 (Big Description) +IFIELD URL, "", "%s" # URL +IFIELD IGNORE, "", "" # Holder for Geocache Type diff --git a/style/saplus.style b/style/saplus.style new file mode 100644 index 000000000..6f8b07b85 --- /dev/null +++ b/style/saplus.style @@ -0,0 +1,28 @@ +# gpsbabel XCSV style file +# +# Format: +# Author: Jim Bensman +# Date: 02/22/04 +# + +DESCRIPTION Delorme Street Atlas Plus + +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER COMMA +RECORD_DELIMITER NEWLINE +BADCHARS ," + +PROLOGUE Name 2,Name,Latitude,Longitude,URL,Type + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD DESCRIPTION, "", "%s" # Name 2 (Big Description) +IFIELD SHORTNAME, "", "%s" # Name +IFIELD LAT_DECIMAL, "", "%f" # Latitude +IFIELD LON_DECIMAL, "", "%f" # Longitude +IFIELD URL, "", "%s" # URL +IFIELD IGNORE, "", "" # Holder for Geocache Type + diff --git a/style/tabsep.style b/style/tabsep.style new file mode 100644 index 000000000..7176e813e --- /dev/null +++ b/style/tabsep.style @@ -0,0 +1,53 @@ +# gpsbabel XCSV style file +# +# Format: Dumps all fields in a traditional Unix tab separated style +# +# The order of the fields (with the exception of LAT_DIR/LON_DIR) was +# the same as documented in README.style when this format was created. +# LAT_DIR/LON_DIR were undocumented, so I stuck them at the end of the +# other lat/lon fields. +# +# However, please add any new gpsbabel fields to the end (to avoid +# upsetting existing applications) regardless of where they land in +# the README.style documentation. +# + +DESCRIPTION All database fields on one tab-separated line + +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER TAB +RECORD_DELIMITER NEWLINE +BADCHARS TAB +FORMAT_TYPE INTERNAL + +# +# INDIVIDUAL DATA FIELDS: +# +IFIELD INDEX, "", "%d" +IFIELD SHORTNAME, "", "%s" +IFIELD DESCRIPTION, "", "%s" +IFIELD NOTES, "", "%s" +IFIELD URL, "", "%s" +IFIELD URL_LINK_TEXT, "", "%s" +IFIELD ICON_DESCR, "", "%s" +IFIELD LAT_DECIMAL, "", "%f" +IFIELD LON_DECIMAL, "", "%f" +IFIELD LAT_INT32DEG, "", "%ld" +IFIELD LON_INT32DEG, "", "%ld" +IFIELD LAT_DECIMALDIR, "", "%f%c" +IFIELD LON_DECIMALDIR, "", "%f%c" +IFIELD LAT_DIRDECIMAL, "", "%c%f" +IFIELD LON_DIRDECIMAL, "", "%c%f" +IFIELD LAT_DIR, "", "%c" +IFIELD LON_DIR, "", "%c" +IFIELD ALT_FEET, "", "%fF" +IFIELD ALT_METERS, "", "%fM" +IFIELD EXCEL_TIME, "", "%f" +IFIELD TIMET_TIME, "", "%ld" +IFIELD GEOCACHE_DIFF,"","%3.1f" +IFIELD GEOCACHE_TERR,"","%3.1f" +IFIELD GEOCACHE_CONTAINER,"","%s" +IFIELD GEOCACHE_TYPE,"","%s" +IFIELD PATH_DISTANCE_MILES,"","%f" +IFIELD PATH_DISTANCE_KM, "", "%f" diff --git a/style/xmap.style b/style/xmap.style new file mode 100644 index 000000000..02bcf0c8b --- /dev/null +++ b/style/xmap.style @@ -0,0 +1,28 @@ +# gpsbabel XCSV style file +# +# Format: Delorme Xmap Conduit +# Author: Alex Mottram +# Date: 12/09/2002 +# +# +# As defined in csv.c/xmap +# + +DESCRIPTION Delorme XMap HH Native .WPT +EXTENSION wpt + +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER COMMASPACE +RECORD_DELIMITER NEWLINE +BADCHARS COMMA + +PROLOGUE BEGIN SYMBOL +EPILOGUE END +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD LAT_DECIMAL, "", "%08.5f" +IFIELD LON_DECIMAL, "", "%08.5f" +IFIELD DESCRIPTION, "", "%s" diff --git a/style/xmapwpt.style b/style/xmapwpt.style new file mode 100644 index 000000000..270ad96ee --- /dev/null +++ b/style/xmapwpt.style @@ -0,0 +1,30 @@ +# gpsbabel XCSV style file +# +# Format: Delorme Xmap HH Street Atlas USA .WPT (PocketPC) +# Author: Alex Mottram +# Date: 12/09/2002 +# +# +DESCRIPTION Delorme XMat HH Street Atlas USA .WPT (PPC) +SHORTLEN 32 +SHORTWHITE 0 + +# +# +# FILE LAYOUT DEFINITIIONS: +# +FIELD_DELIMITER COLON +RECORD_DELIMITER NEWLINE +BADCHARS COLON + +# +# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE: +# +IFIELD CONSTANT, "1296126539", "%s" +IFIELD CONSTANT, "1481466224", "%s" +IFIELD LAT_INT32DEG, "", "%d" +IFIELD LON_INT32DEG, "", "%d" +IFIELD CONSTANT, "3137157", "%s" +IFIELD SHORTNAME, "", "%-.31s" +IFIELD IGNORE, "", "%-.31s" +IFIELD DESCRIPTION, "", "%-.78s" diff --git a/testo b/testo new file mode 100644 index 000000000..cba457c9a --- /dev/null +++ b/testo @@ -0,0 +1,599 @@ +GPSBABEL_FREEZE_TIME=y +export GPSBABEL_FREEZE_TIME + +PNAME=${PNAME:-./gpsbabel} +DIFF=${DIFF:-diff} +OD=${OD:-od -Ax -txC -v} + +TMPDIR=/tmp/gpsbabel.$$ +mkdir -p $TMPDIR +trap "rm -fr $TMPDIR" 0 1 2 3 15 + +bincompare() +{ + rm -f ${TMPDIR}/bc1 + rm -f ${TMPDIR}/bc2 + ${OD} $1 >${TMPDIR}/bc1 + ${OD} $2 >${TMPDIR}/bc2 + ${DIFF} -u ${TMPDIR}/bc1 ${TMPDIR}/bc2 || { + echo ERROR binary comparing $* + exit 1 + } +} + +compare() +{ + ${DIFF} $* || { + echo ERROR comparing $* + exit 1 + } +} + +sort_and_compare() +{ + sort $1 > $TMPDIR/s1 + sort $2 > $TMPDIR/s2 + compare $TMPDIR/s1 $TMPDIR/s2 +} + + +# Geocaching .loc +rm -f ${TMPDIR}/gl.loc +${PNAME} -i geo -f geocaching.loc -o geo -F ${TMPDIR}/gl.loc +compare ${TMPDIR}/gl.loc reference + +# GPSUtil +rm -f ${TMPDIR}/gu.wpt ${TMPDIR}/1.gpx ${TMPDIR}/2.gpx +${PNAME} -i geo -f geocaching.loc -o gpsutil -F ${TMPDIR}/gu.wpt +compare ${TMPDIR}/gu.wpt reference +${PNAME} -i gpsutil -f ${TMPDIR}/gu.wpt -o gpx -F ${TMPDIR}/1.gpx +${PNAME} -i gpsutil -f reference/gu.wpt -o gpx -F ${TMPDIR}/2.gpx +compare ${TMPDIR}/1.gpx ${TMPDIR}/2.gpx + +# GPSman +rm -f ${TMPDIR}/gm.gm ${TMPDIR}/gm.gm+ +${PNAME} -i geo -f geocaching.loc -o gpsman -F ${TMPDIR}/gm.gm +${PNAME} -i gpsman -f ${TMPDIR}/gm.gm -o gpsutil -F ${TMPDIR}/gm.gm+ +compare ${TMPDIR}/gm.gm+ ${TMPDIR}/gu.wpt + +# GPX +rm -f ${TMPDIR}/gl.gpx ${TMPDIR}/gpx.gpx +${PNAME} -i geo -f geocaching.loc -o gpx -F ${TMPDIR}/gl.gpx +${PNAME} -i gpx -f ${TMPDIR}/gl.gpx -o gpsutil -F ${TMPDIR}/gpx.gpx +compare ${TMPDIR}/gpx.gpx ${TMPDIR}/gu.wpt + +# Magellan Mapsend +rm -f ${TMPDIR}/mm.mapsend ${TMPDIR}/mm.gps +${PNAME} -i geo -f geocaching.loc -o mapsend -F ${TMPDIR}/mm.mapsend +${PNAME} -i mapsend -f ${TMPDIR}/mm.mapsend -o gpsutil -F ${TMPDIR}/mm.gps +compare ${TMPDIR}/mm.gps ${TMPDIR}/gu.wpt + +# Magellan serial +# TODO + +# Tiger +# This one is a little tacky, becuase it's a very lossy format. +# so we simply test we can write it, and then read it and write it and +# get an identical file back. +rm -f ${TMPDIR}/tiger +${PNAME} -i geo -f geocaching.loc -o tiger -F ${TMPDIR}/tiger +${PNAME} -i tiger -f ${TMPDIR}/tiger -o tiger -F ${TMPDIR}/tiger2 +compare ${TMPDIR}/tiger ${TMPDIR}/tiger2 + +# CSV (Comma separated value) data. + +${PNAME} -i geo -f geocaching.loc -o csv -F ${TMPDIR}/csv.csv +${PNAME} -i csv -f ${TMPDIR}/csv.csv -o csv -F ${TMPDIR}/csv2.csv +compare ${TMPDIR}/csv2.csv ${TMPDIR}/csv.csv + +# +# Delorme TopoUSA 4 is a CSV strain. +# +rm -f ${TMPDIR}/xmap-1.gpx ${TMPDIR}/xmap-2.gpx ${TMPDIR}/xmap +${PNAME} -i xmap -f reference/xmap -o xmap -F ${TMPDIR}/xmap +${PNAME} -i xmap -f reference/xmap -o gpx -F ${TMPDIR}/xmap-1.gpx +${PNAME} -i xmap -f ${TMPDIR}/xmap -o gpx -F ${TMPDIR}/xmap-2.gpx +compare ${TMPDIR}/xmap-1.gpx ${TMPDIR}/xmap-2.gpx +compare reference/xmap ${TMPDIR}/xmap + +# PCX (Garmin mapsource import) file format +rm -f ${TMPDIR}/mm.pcx ${TMPDIR}/pcx.gps +${PNAME} -i geo -f geocaching.loc -o pcx -F ${TMPDIR}/mm.pcx +${PNAME} -i pcx -f ${TMPDIR}/mm.pcx -o gpsutil -F ${TMPDIR}/pcx.gps +compare ${TMPDIR}/mm.gps ${TMPDIR}/gu.wpt + +# Magellan file format +${PNAME} -i magellan -f reference/magfile -o magellan -F ${TMPDIR}/magfile +compare ${TMPDIR}/magfile reference/magfile + +# Navitrak DNA marker format +${PNAME} -i dna -f reference/dnatest.txt -o dna -F ${TMPDIR}/dnatest.txt +compare ${TMPDIR}/dnatest.txt reference/dnatest.txt + +# PSP (PocketStreets 2002 Pushpin (.PSP)) file format. Use mxf as an +# intermediate format to avoid binary FP anomalies on compareerent platforms. +rm -f ${TMPDIR}/psp.mxf ${TMPDIR}/mxf.psp +${PNAME} -i psp -f reference/ps.psp -o mxf -F ${TMPDIR}/psp.mxf +${PNAME} -i geo -f geocaching.loc -o mxf -F ${TMPDIR}/mxf.psp +compare ${TMPDIR}/psp.mxf ${TMPDIR}/mxf.psp +${PNAME} -i psp -f reference/ps.psp -o gpx -F ${TMPDIR}/psp1.gpx +${PNAME} -i psp -f reference/ps.psp -o psp -F ${TMPDIR}/xxx.psp +${PNAME} -i psp -f ${TMPDIR}/xxx.psp -o gpx -F ${TMPDIR}/psp2.gpx +compare ${TMPDIR}/psp1.gpx ${TMPDIR}/psp2.gpx + +# MXF (Maptech Exchange Format) file format +rm -f ${TMPDIR}/mx.mxf ${TMPDIR}/mxf.mxf +${PNAME} -i mxf -f reference/mxf.mxf -o mxf -F ${TMPDIR}/mx.mxf +${PNAME} -i mxf -f ${TMPDIR}/mx.mxf -o mxf -F ${TMPDIR}/mxf.mxf +compare ${TMPDIR}/mxf.mxf reference + +# tmpro (TopoMapPro Places) file format +rm -f ${TMPDIR}/topomappro.txt ${TMPDIR}/mxf.mxf +${PNAME} -i tmpro -f reference/topomappro.txt -o tmpro -F ${TMPDIR}/tmp.txt +${PNAME} -i tmpro -f ${TMPDIR}/tmp.txt -o tmpro -F ${TMPDIR}/topomappro.txt +compare ${TMPDIR}/topomappro.txt reference + +# TPG (NG Topo!) file format +# This is hard to test as the datum conversions create minute +# inconsistencies in the coordinates. So.. we test our i/o +# against a format that rounds higher than we care to compare +# for binary data. +rm -f ${TMPDIR}/topo.mxf ${TMPDIR}/tpg.mxf ${TMPDIR}/geo.tpg +${PNAME} -i geo -f geocaching.loc -o tpg -F ${TMPDIR}/geo.tpg +${PNAME} -i tpg -f ${TMPDIR}/geo.tpg -o mxf -F ${TMPDIR}/tpg.mxf +${PNAME} -i tpg -f reference/tpg.tpg -o mxf -F ${TMPDIR}/topo.mxf +compare ${TMPDIR}/tpg.mxf ${TMPDIR}/topo.mxf + +# OZI (OziExplorer 1.1) file format +rm -f ${TMPDIR}/oz.wpt ${TMPDIR}/ozi.wpt +${PNAME} -i ozi -f reference/ozi.wpt -o ozi -F ${TMPDIR}/oz.wpt +${PNAME} -i ozi -f ${TMPDIR}/oz.wpt -o ozi -F ${TMPDIR}/ozi.wpt +compare ${TMPDIR}/ozi.wpt reference + +# Holux support is a little funky to test. Becuase it loses precision, +# if we convert it to another format, we lose accuracy (rounding) in the +# coords, so converting it so something else and comparing it never works. +# So we verify that we can read the reference and write it and get an +# identical reference. +${PNAME} -i holux -f reference/paris.wpo -o holux -F ${TMPDIR}/paris.wpo +compare reference/paris.wpo ${TMPDIR}/paris.wpo + +# Magellan NAV Companion for PalmOS +# This format is hard to test, because each record and the database itself +# contains the time of creation, so two otherwise identical files won't +# compare accurately. In any case, the files are binary so compare wouldn't +# like them. So, we convert the reference file to gpsutil and the converted +# file to gpsutil and make sure they're the same, and that they're the same +# as one converted on a known-working installation. Unfortunately, this does +# not verify that the appinfo block was written correctly. However, it does +# successfully test for some endianness errors that might otherwise go +# unnoticed. +rm -f ${TMPDIR}/magnav.pdb ${TMPDIR}/magnav.gpu ${TMPDIR}/magnavt.gpu +${PNAME} -i geo -f geocaching.loc -o magnav -F ${TMPDIR}/magnav.pdb +${PNAME} -i magnav -f ${TMPDIR}/magnav.pdb -o gpsutil -F ${TMPDIR}/magnav.gpu +${PNAME} -i magnav -f reference/magnav.pdb -o gpsutil -F ${TMPDIR}/magnavt.gpu +compare ${TMPDIR}/magnavt.gpu ${TMPDIR}/magnav.gpu +compare reference/gu.wpt ${TMPDIR}/magnav.gpu + +rm -f ${TMPDIR}/magnav.pdb +${PNAME} -i geo -f geocaching.loc -o magnav -F ${TMPDIR}/magnav.pdb +bincompare ${TMPDIR}/magnav.pdb reference/magnav.pdb + + + +# GPSPilot Tracker for PalmOS +# This test is eerily similar to the NAV Companion test. In fact, the +# converted reference file (magnavr.gpu) is identical. +rm -f ${TMPDIR}/gpspilot.pdb ${TMPDIR}/gpspilot.gpu ${TMPDIR}/gpspil_t.gpu +${PNAME} -i geo -f geocaching.loc -o gpspilot -F ${TMPDIR}/gpspilot.pdb +${PNAME} -i gpspilot -f ${TMPDIR}/gpspilot.pdb -o gpsutil -F ${TMPDIR}/gpspilot.gpu +${PNAME} -i gpspilot -f reference/gpspilot.pdb -o gpsutil -F ${TMPDIR}/gpspil_t.gpu +compare ${TMPDIR}/gpspil_t.gpu ${TMPDIR}/gpspilot.gpu +compare reference/gu.wpt ${TMPDIR}/gpspilot.gpu + +# Cetus GPS for PalmOS +# This test is also similar to the NAV Companion test. +rm -f ${TMPDIR}/cetus.pdb ${TMPDIR}/cetus.gpu ${TMPDIR}/cetust.gpu +${PNAME} -i geo -f geocaching.loc -o cetus -F ${TMPDIR}/cetus.pdb +${PNAME} -i cetus -f ${TMPDIR}/cetus.pdb -o gpsutil -F ${TMPDIR}/cetus.gpu +${PNAME} -i cetus -f reference/cetus.pdb -o gpsutil -F ${TMPDIR}/cetust.gpu +compare ${TMPDIR}/cetust.gpu ${TMPDIR}/cetus.gpu +compare reference/cetus.gpu ${TMPDIR}/cetus.gpu + +# QuoVadis GPS for PalmOS +# This test is derived from the Cetus test above. +rm -f ${TMPDIR}/quovadis.pdb ${TMPDIR}/quovadis.gpu ${TMPDIR}/quovadist.gpu +${PNAME} -i geo -f geocaching.loc -o quovadis -F ${TMPDIR}/quovadis.pdb +${PNAME} -i quovadis -f ${TMPDIR}/quovadis.pdb -o gpsutil -F ${TMPDIR}/quovadis.gpu +${PNAME} -i quovadis -f reference/quovadis.pdb -o gpsutil -F ${TMPDIR}/quovadist.gpu +compare ${TMPDIR}/quovadist.gpu ${TMPDIR}/quovadis.gpu +compare reference/quovadis.gpu ${TMPDIR}/quovadis.gpu + +# GpsDrive +rm -f ${TMPDIR}/gpsdrive.txt +${PNAME} -i geo -f geocaching.loc -o gpsdrive -F ${TMPDIR}/gpsdrive.txt +compare ${TMPDIR}/gpsdrive.txt reference +${PNAME} -i gpsdrive -f reference/gpsdrive.txt -o gpsdrive -F ${TMPDIR}/gpsdrive2.txt +compare ${TMPDIR}/gpsdrive2.txt reference/gpsdrive.txt + +# XMapHH Street Atlas USA file format +rm -f ${TMPDIR}/xmapwpt.wpt ${TMPDIR}/xmapwpt.xmapwpt +${PNAME} -i xmapwpt -f reference/xmapwpt.wpt -o xmapwpt -F ${TMPDIR}/xmapwpt.xmapwpt +${PNAME} -i xmapwpt -f ${TMPDIR}/xmapwpt.xmapwpt -o xmapwpt -F ${TMPDIR}/xmapwpt.wpt +compare ${TMPDIR}/xmapwpt.wpt reference + +# XCSV +# Test that we can parse a style file, and read and write data in the +# same xcsv format (a complete test is virtually impossible). +echo "RECORD_DELIMITER NEWLINE" > ${TMPDIR}/testo.style +echo "FIELD_DELIMITER COMMA" >> ${TMPDIR}/testo.style +echo "BADCHARS COMMA" >> ${TMPDIR}/testo.style +echo "PROLOGUE Header" >> ${TMPDIR}/testo.style +echo "EPILOGUE Footer" >> ${TMPDIR}/testo.style +echo "IFIELD SHORTNAME,,%s" >> ${TMPDIR}/testo.style +echo "IFIELD LAT_DIRDECIMAL,,%c%lf" >> ${TMPDIR}/testo.style +echo "IFIELD LON_DECIMALDIR,,%lf%c" >> ${TMPDIR}/testo.style +rm -f ${TMPDIR}/xcsv.geo ${TMPDIR}/xcsv.xcsv +${PNAME} -i geo -f geocaching.loc -o xcsv,style=${TMPDIR}/testo.style -F ${TMPDIR}/xcsv.geo +${PNAME} -i xcsv,style=${TMPDIR}/testo.style -f ${TMPDIR}/xcsv.geo -o xcsv,style=${TMPDIR}/testo.style -F ${TMPDIR}/xcsv.xcsv +compare ${TMPDIR}/xcsv.geo ${TMPDIR}/xcsv.xcsv + +# Garmin Mapsource This is a binary format with some undocumented +# fields. This test is therefore intentionally vague. We read a file, +# convert it to GPX, then write a file as MPS, then read it back and +# write it as GPX and compare them. Since we're writing both GPX files +# ourselves from the same version, we're immune to changes in our own +# GPX output. + +rm -fr ${TMPDIR}/ms.gpx ${TMPDIR}/ms[12].gpx +${PNAME} -i mapsource -f reference/mapsource.mps -o gpx -F ${TMPDIR}/ms1.gpx +${PNAME} -i mapsource -f reference/mapsource.mps -o mapsource -F ${TMPDIR}/ms.mps +${PNAME} -i mapsource -f ${TMPDIR}/ms.mps -o gpx -F ${TMPDIR}/ms2.gpx +compare ${TMPDIR}/ms1.gpx ${TMPDIR}/ms2.gpx + +# +# MRCB mapsource track test +# +rm -f ${TMPDIR}/mps-track.mps +${PNAME} -t -i mapsource -f reference/track/mps-track.mps -o mapsource,mpsverout=3 \ + -F ${TMPDIR}/mps-track.mps +compare ${TMPDIR}/mps-track.mps reference/track/ + +# Now do a test of reading waypoints from a track-only file - should have an empty result +rm -f ${TMPDIR}/mps-track.mps +${PNAME} -i mapsource -f reference/track/mps-track.mps -o mapsource,mpsverout=3 \ + -F ${TMPDIR}/mps-track.mps +compare ${TMPDIR}/mps-track.mps reference/mps-empty.mps + +# +# MRCB mapsource route test +# +rm -f ${TMPDIR}/mps-route.mps +${PNAME} -r -i mapsource -f reference/route/route.mps -o mapsource,mpsverout=4 \ + -F ${TMPDIR}/mps-route.mps +compare ${TMPDIR}/mps-route.mps reference/route/route.mps + +# Now do a test of reading tracks from a route-only file - should have an empty result +rm -f ${TMPDIR}/mps-route.mps +${PNAME} -t -i mapsource -f reference/route/route.mps -o mapsource,mpsverout=3 \ + -F ${TMPDIR}/mps-route.mps +compare ${TMPDIR}/mps-route.mps reference/mps-empty.mps + +# +# Geocaching Database is a binary Palm format that, like the GPX variants +# has a zillion "equivalent" encodings of any given record set. So we +# read the reference file, spin it to GPX and back to GCDB and then spin +# that one to GPX. +# + +${PNAME} -i gcdb -f reference/GeocachingDB.PDB -o gpx -F ${TMPDIR}/gcdb1.gpx \ + -o gcdb -F ${TMPDIR}/gcdb1.pdb +${PNAME} -i gpx -f ${TMPDIR}/gcdb1.gpx -o gpx -F ${TMPDIR}/gcdb2.gpx +compare ${TMPDIR}/gcdb1.gpx ${TMPDIR}/gcdb1.gpx + +# +# Duplicate filter - Since filters have no format of their own, we use csv +# as an intermediate format for testing the filter. +# +rm -f ${TMPDIR}/filterdupe.csv1 ${TMPDIR}/filterdupe.csv2 +${PNAME} -i geo -f geocaching.loc -o csv -F ${TMPDIR}/filterdupe.csv1 +${PNAME} -i geo -f geocaching.loc -f geocaching.loc -x duplicate,shortname \ + -o csv -F ${TMPDIR}/filterdupe.csv2 +sort_and_compare ${TMPDIR}/filterdupe.csv1 ${TMPDIR}/filterdupe.csv2 + +# +# Position filter - Since very small distances are essentialy a duplicate +# position filter, we can test very similarly to the duplicate filter. +# +rm -f ${TMPDIR}/filterpos.csv1 ${TMPDIR}/filterpos.csv2 +${PNAME} -i geo -f geocaching.loc -o csv -F ${TMPDIR}/filterpos.csv1 +${PNAME} -i geo -f geocaching.loc -f geocaching.loc -x position,distance=5f \ + -o csv -F ${TMPDIR}/filterpos.csv2 +sort_and_compare ${TMPDIR}/filterpos.csv1 ${TMPDIR}/filterpos.csv2 + +# +# Radius filter +# +rm -f ${TMPDIR}/radius.csv +${PNAME} -i geo -f geocaching.loc \ + -x radius,lat=35.9720,lon=-87.1347,distance=14.7 \ + -o csv -F ${TMPDIR}/radius.csv +compare ${TMPDIR}/radius.csv reference/ + +# +# magellan SD card waypoint / route format +# +rm -f ${TMPDIR}/magellan.rte +${PNAME} -r -i magellan -f reference/route/magellan.rte -o magellan \ + -F ${TMPDIR}/magellan.rte +compare ${TMPDIR}/magellan.rte reference/route/magellan.rte + +# +# GPX routes -- since GPX contains a date stamp, tests will always +# fail, so we use magellan as an interim format... +# +rm -f ${TMPDIR}/gpxroute.gpx ${TMPDIR}/maggpx.rte +${PNAME} -r -i gpx -f reference/route/route.gpx -o gpx \ + -F ${TMPDIR}/gpxroute.gpx +${PNAME} -r -i gpx -f ${TMPDIR}/gpxroute.gpx -o magellan \ + -F ${TMPDIR}/maggpx.rte +compare ${TMPDIR}/maggpx.rte reference/route/magellan.rte + +# +# GPX tracks -- since GPX contains a date stamp, tests will always +# fail, so we use magellan as an interim format... +# +rm -f ${TMPDIR}/gpxtrack.gpx ${TMPDIR}/maggpx.trk +${PNAME} -t -i gpx -f reference/track/tracks.gpx -o gpx \ + -F ${TMPDIR}/gpxtrack.gpx +${PNAME} -t -i magellan -f reference/track/meridian.trk -o gpx \ + -F ${TMPDIR}/maggpx.trk +compare ${TMPDIR}/maggpx.trk ${TMPDIR}/gpxtrack.gpx + +# +# MAPSEND waypoint / route format +# +rm -f ${TMPDIR}/route.mapsend +${PNAME} -r -i mapsend -f reference/route/route.mapsend -o mapsend \ + -F ${TMPDIR}/route.mapsend +compare ${TMPDIR}/route.mapsend reference/route/ + +# +# MAPSEND track format +# +rm -f ${TMPDIR}/mapsend.trk +${PNAME} -t -i mapsend -f reference/track/mapsend.trk -o mapsend \ + -F ${TMPDIR}/mapsend.trk +compare ${TMPDIR}/mapsend.trk reference/track/ + +# +# copilot +# +rm -f ${TMPDIR}/copilot.pdb +${PNAME} -i copilot -f reference/UKultralight.pdb -o copilot -F ${TMPDIR}/cop.pdb +${PNAME} -i copilot -f reference/UKultralight.pdb -o gpx -F ${TMPDIR}/cop1.gpx +${PNAME} -i copilot -f ${TMPDIR}/cop.pdb -o gpx -F ${TMPDIR}/cop2.gpx +compare ${TMPDIR}/cop1.gpx ${TMPDIR}/cop2.gpx + +# +# EasyGPS. Another binary format. +# +rm -f ${TMPDIR}/easy.loc +${PNAME} -i easygps -f reference/easygps.loc -o easygps -F ${TMPDIR}/ez.loc +${PNAME} -i easygps -f reference/easygps.loc -o gpx -F ${TMPDIR}/ez1.gpx +${PNAME} -i easygps -f ${TMPDIR}/ez.loc -o gpx -F ${TMPDIR}/ez2.gpx +compare ${TMPDIR}/ez1.gpx ${TMPDIR}/ez2.gpx + +# +# GPilotS. A Palm format. Another binary format that +# +# rm -f ${TMPDIR/gpilots.l +#${PNAME} -i easygps -f reference/gpilots.pdb -o gpx -F ${TMPDIR}/gp.gpx +${PNAME} -i geo -f geocaching.loc -o gpilots -F ${TMPDIR}/blah.pdb +${PNAME} -i gpilots -f ${TMPDIR}/blah.pdb -o gpx -F ${TMPDIR}/1.gpx +${PNAME} -i gpilots -f reference/gpilots.pdb -o gpx -F ${TMPDIR}/2.gpx +compare ${TMPDIR}/1.gpx ${TMPDIR}/2.gpx +#${PNAME} -i easygps -f reference/gpilots.pdb -o gpx -F ${TMPDIR}/gp.gpx + +# +# Navicache. +${PNAME} -i navicache -f reference/navicache.xml -o gpsutil -F ${TMPDIR}/navi.wpt +compare ${TMPDIR}/navi.wpt reference/navicache.ref +# + +# PsiTrex. A text format that can't be handled by XCSV due to context of +# data based on other data values in the file +# Waypoints first +rm -f ${TMPDIR}/psit-ww.txt ${TMPDIR}/psit-ww.mps +${PNAME} -i psitrex -f reference/psitwpts.txt -o mapsource -F ${TMPDIR}/psit-ww.mps +${PNAME} -i mapsource -f ${TMPDIR}/psit-ww.mps -o psitrex -F ${TMPDIR}/psit-ww.txt +compare reference/psitwpts.txt ${TMPDIR}/psit-ww.txt + +# Now test correct "empty" handling - ask for routes when there aren't any +# Uses mapsource as the empty handling for this has already happened above +rm -f ${TMPDIR}/psit-wr.mps +${PNAME} -r -i psitrex -f reference/psitwpts.txt -o mapsource,mpsverout=3 -F ${TMPDIR}/psit-wr.mps +compare reference/mps-empty.mps ${TMPDIR}/psit-wr.mps + +# Routes next +rm -f ${TMPDIR}/psit-rr.txt ${TMPDIR}/psit-rr.mps +${PNAME} -r -i psitrex -f reference/route/psitrtes.txt -o mapsource -F ${TMPDIR}/psit-rr.mps +${PNAME} -r -i mapsource -f ${TMPDIR}/psit-rr.mps -o psitrex -F ${TMPDIR}/psit-rr.txt +compare reference/route/psitrtes.txt ${TMPDIR}/psit-rr.txt + +# Now test correct "empty" handling - ask for tracks when there aren't any +# Uses mapsource as the empty handling for this has already happened above +rm -f ${TMPDIR}/psit-rt.mps +${PNAME} -t -i psitrex -f reference/route/psitrtes.txt -o mapsource,mpsverout=3 -F ${TMPDIR}/psit-rt.mps +compare reference/mps-empty.mps ${TMPDIR}/psit-rt.mps + +# Tracks last +rm -f ${TMPDIR}/psit-tt.txt ${TMPDIR}/psit-tt.mps +${PNAME} -t -i psitrex -f reference/track/psittrks.txt -o mapsource -F ${TMPDIR}/psit-tt.mps +${PNAME} -t -i mapsource -f ${TMPDIR}/psit-tt.mps -o psitrex -F ${TMPDIR}/psit-tt.txt +compare reference/track/psittrks.txt ${TMPDIR}/psit-tt.txt + +# Now test correct "empty" handling - ask for waypoints when there aren't any +# Uses mapsource as the empty handling for this has already happened above +rm -f ${TMPDIR}/psit-tw.mps +${PNAME} -i psitrex -f reference/track/psittrks.txt -o mapsource,mpsverout=3 -F ${TMPDIR}/psit-tw.mps +compare reference/mps-empty.mps ${TMPDIR}/psit-tw.mps + +# +# Arc Distance filter +# +rm -f ${TMPDIR}/arcdist.txt +${PNAME} -i xmap -f reference/arcdist_input.txt \ + -x arc,file=reference/arcdist_arc.txt,distance=1 \ + -o xmap -F ${TMPDIR}/arcdist.txt +compare ${TMPDIR}/arcdist.txt reference/arcdist_output.txt + +# +# Polygon filter +# +rm -f ${TMPDIR}/polygon.txt +${PNAME} -i xmap -f reference/arcdist_input.txt \ + -x polygon,file=reference/polygon_allencty.txt \ + -o xmap -F ${TMPDIR}/polygon.txt +compare ${TMPDIR}/polygon.txt reference/polygon_output.txt + +# +# Simplify filter +# +rm -f ${TMPDIR}/simplify.txt +${PNAME} -r -i gpx -f reference/route/route.gpx \ + -x simplify,count=10 \ + -o arc -F ${TMPDIR}/simplify.txt +compare ${TMPDIR}/simplify.txt reference/simplify_output.txt + +# +# Route reversal filter. Do it twice and be sure we get what we +# started with. +# +rm -f ${TMPDIR}/reverse1.arc ${TMPDIR}/reverse2.arc ${TMPDIR}/reference.arc +${PNAME} -r -i gpx -f reference/route/route.gpx \ + -o arc -F ${TMPDIR}/reference.arc +${PNAME} -r -i gpx -f reference/route/route.gpx \ + -x reverse \ + -o arc -F ${TMPDIR}/reverse1.arc +${PNAME} -r -i gpx -f reference/route/route.gpx \ + -x reverse \ + -x reverse \ + -o arc -F ${TMPDIR}/reverse2.arc +# Verify the first and last are the same +compare ${TMPDIR}/reference.arc ${TMPDIR}/reverse2.arc +# Verify the first and second are different. +#${DIFF} ${TMPDIR}/reverse1.arc ${TMPDIR}/reverse2.arc > /dev/null && { +# echo ERROR Failed reversal test. +# exit 1 +#} + +# parkrrrr: This isn't a straightforward compare; we *want* it to fail. +# Obviously this test should just be rewritten with a new reference. +#compare ${TMPDIR}/reverse1.arc ${TMPDIR}/reverse2.arc + +# +# Geoniche: No reference file was available, so we created one and just +# test it against itself. +# +rm -f ${TMPDIR}/gn.pdb ${TMPDIR}/1.gpx ${TMPDIR}/2.gpx +${PNAME} -i geoniche -f reference/geoniche.pdb -o geoniche -F ${TMPDIR}/gn.pdb +${PNAME} -i geoniche -f reference/geoniche.pdb -o gpx -F ${TMPDIR}/1.gpx +${PNAME} -i geoniche -f ${TMPDIR}/gn.pdb -o gpx -F ${TMPDIR}/2.gpx +compare ${TMPDIR}/1.gpx ${TMPDIR}/2.gpx + +# +# saroute covers *.anr, *.rte, and *.rtd, but I only have an .anr for testing. +# Unfortunately for us, this is a read-only format for now. +# +${PNAME} -t -i saroute -f reference/track/i65.anr -o gpx -F ${TMPDIR}/gpl1.gpx +${PNAME} -t -i gpx -f reference/track/i65.anr.gpx -o gpx -F ${TMPDIR}/gpl2.gpx +compare ${TMPDIR}/gpl1.gpx ${TMPDIR}/gpl2.gpx + +# +# Delorme GPL file. This is sort of a track format. +# +rm -f ${TMPDIR}/gpl1.gpx ${TMPDIR}/gpl2.gpx ${TMPDIR}/gpl1.gpl +${PNAME} -t -i gpl -f reference/track/webpark1.gpl -o gpx -F ${TMPDIR}/gpl1.gpx +${PNAME} -t -i gpl -f reference/track/webpark1.gpl -o gpl -F ${TMPDIR}/gpl1.gpl +${PNAME} -t -i gpl -f ${TMPDIR}/gpl1.gpl -o gpx -F ${TMPDIR}/gpl2.gpx +compare ${TMPDIR}/gpl1.gpx ${TMPDIR}/gpl2.gpx + +# +# NetStumbler Summary File (read-only) +# +rm -f ${TMPDIR}/netstumbler.mps +${PNAME} -i netstumbler -f reference/netstumbler.txt -o mapsource -F ${TMPDIR}/netstumbler.mps +bincompare ${TMPDIR}/netstumbler.mps reference/netstumbler.mps + +# +# IGC tests +# +rm -f ${TMPDIR}/igc*out +${PNAME} -i gpx -f reference/igc1.gpx -o igc -F ${TMPDIR}/igc.out +sed '/^LXXXGenerated by GPSBabel Version/d' ${TMPDIR}/igc.out > ${TMPDIR}/igc_sed.out +compare ${TMPDIR}/igc_sed.out reference/igc1_igc.out + +${PNAME} -i igc -f ${TMPDIR}/igc.out -o gpx -F ${TMPDIR}/igc.gpx +compare ${TMPDIR}/igc.gpx reference/igc1_gpx.out + +${PNAME} -i gpx -f ${TMPDIR}/igc.gpx -o igc -F ${TMPDIR}/igc.out +sed '/^LXXXGenerated by GPSBabel Version/d' ${TMPDIR}/igc.out > ${TMPDIR}/igc_sed.out +compare ${TMPDIR}/igc_sed.out reference/igc1_igc.out + +${PNAME} -i gpx -f reference/igc1_baro.gpx -i igc -f reference/igc1_igc.out -o igc,timeadj=auto -F ${TMPDIR}/igc.out +sed '/^LXXXGenerated by GPSBabel Version/d' ${TMPDIR}/igc.out > ${TMPDIR}/igc_sed.out +compare ${TMPDIR}/igc_sed.out reference/igc1_3d.out + + +${PNAME} -i igc -f reference/igc2.igc -o gpx -F ${TMPDIR}/igc.gpx +compare ${TMPDIR}/igc.gpx reference/igc2_gpx.out + +${PNAME} -i gpx -f ${TMPDIR}/igc.gpx -o igc -F ${TMPDIR}/igc.out +sed '/^LXXXGenerated by GPSBabel Version/d' ${TMPDIR}/igc.out > ${TMPDIR}/igc_sed.out +compare ${TMPDIR}/igc_sed.out reference/igc2_igc.out + +${PNAME} -i igc -f ${TMPDIR}/igc.out -o gpx -F ${TMPDIR}/igc.gpx +compare ${TMPDIR}/igc.gpx reference/igc2_gpx.out + + +# +# XCSV "human readable" tests +# +rm -f ${TMPDIR}/humanread.out +${PNAME} -i xcsv,style=reference/humanread.style -f reference/human.in -o arc -F ${TMPDIR}/humanread.out +compare ${TMPDIR}/humanread.out reference/humanread.out + +rm -f ${TMPDIR}/humanwrite.out +${PNAME} -i xcsv,style=reference/humanread.style -f reference/human.in -o xcsv,style=reference/humanwrite.style -F ${TMPDIR}/humanwrite.out +compare ${TMPDIR}/humanwrite.out reference/humanwrite.out + +# +# XCSV "path distance" test +# +rm -f ${TMPDIR}/pathdist.out +${PNAME} -i magellan -f reference/dusky.trk -o xcsv,style=reference/gnuplot.style -F ${TMPDIR}/pathdist.out +compare ${TMPDIR}/pathdist.out reference/dusky.gnuplot + +# hsandv +rm -f ${TMPDIR}/hsandv.exp ${TMPDIR}/1.exp ${TMPDIR}/1.exp ${TMPDIR}/Glad_5.exp +${PNAME} -i geo -f geocaching.loc -o hsandv -F ${TMPDIR}/hsandv.exp +compare ${TMPDIR}/hsandv.exp reference +#the hsandv format is too lossy to do this test :( +#${PNAME} -i hsandv -f ${TMPDIR}/hsandv.exp -o geo -F ${TMPDIR}/1.exp +#${PNAME} -i hsandv -f reference/hsandv.exp -o geo -F ${TMPDIR}/2.exp +#compare ${TMPDIR}/1.exp ${TMPDIR}/2.exp +#test conversion from v4 to v5 files +${PNAME} -i hsandv -f reference/Glad_4.exp -o hsandv -F ${TMPDIR}/Glad_5.exp +# FIXME: Can't compare directly because of potential FP rounding. +# FIXME: compare ${TMPDIR}/Glad_5.exp reference + +# +# stack filter tests +# These don't actually test for proper behavior, for now, but they do +# exercise all of the currently-extant filter code. +# + +${PNAME} -i geo -f geocaching.loc -x stack,push,copy,nowarn -x stack,push,copy -x stack,push -x stack,pop,replace -x stack,pop,append -x stack,push,copy -x stack,pop,discard -x stack,swap,depth=1 -o arc -F ${TMPDIR}/stackfilt.txt + +exit 0 diff --git a/text.c b/text.c new file mode 100644 index 000000000..b369e7500 --- /dev/null +++ b/text.c @@ -0,0 +1,231 @@ +/* + Output only format for Human Readable formats. + + Copyright (C) 2004 Scott Brynen, scott (at) brynen.com + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA +*/ + + +#include "defs.h" +#include "jeeps/gpsmath.h" +#include + +static FILE *file_out; +static void *mkshort_handle; + +static char *suppresssep = NULL; +static char *encrypt = NULL; +static char *includelogs = NULL; + +#define MYNAME "TEXT" + +static +arglist_t text_args[] = { + { "nosep", &suppresssep, + "Suppress separator lines between waypoints", + NULL, ARGTYPE_BOOL }, + { "encrypt", &encrypt, + "Encrypt hints using ROT13", NULL, ARGTYPE_BOOL }, + { "logs", &includelogs, + "Include groundspeak logs if present", NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + + + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "w", MYNAME); + mkshort_handle = mkshort_new_handle(); +} + +static void +wr_deinit(void) +{ + fclose(file_out); + mkshort_del_handle(mkshort_handle); +} + +static void +text_disp(const waypoint *wpt) +{ + int latint, lonint; + char tbuf[1024]; + time_t tm = wpt->creation_time; + long utmz; + double utme, utmn; + char utmzc; + + lonint = abs(wpt->longitude); + latint = abs(wpt->latitude); + + GPS_Math_WGS84_To_UTM_EN(wpt->latitude, wpt->longitude, + &utme, &utmn, &utmz, &utmzc); + + if (tm == 0) + tm = time(NULL); + strftime(tbuf, sizeof(tbuf), "%d-%b-%Y", localtime(&tm)); + + fprintf(file_out, "%-16s %c%d %06.3f %c%d %06.3f (%ld%c %6.0f %7.0f)", + (global_opts.synthesize_shortnames) ? mkshort(mkshort_handle, wpt->description) : wpt->shortname, + wpt->latitude < 0 ? 'S' : 'N', abs(latint), 60.0 * (fabs(wpt->latitude) - latint), + wpt->longitude < 0 ? 'W' : 'E', abs(lonint), 60.0 * (fabs(wpt->longitude) - lonint), + utmz, utmzc, utme, utmn); + if (wpt->altitude != unknown_alt) + fprintf (file_out, " alt: %1.1f", wpt->altitude); + fprintf (file_out, "\n"); + if (strcmp(wpt->description, wpt->shortname)) { + fprintf(file_out, "%s\n", wpt->description); + } + if (wpt->gc_data.terr) { + if (wpt->gc_data.desc_short.utfstring) { + char *stripped_html = strip_html(&wpt->gc_data.desc_short); + fprintf (file_out, "\n%s\n", stripped_html); + xfree(stripped_html); + } + if (wpt->gc_data.desc_long.utfstring) { + char *stripped_html = strip_html(&wpt->gc_data.desc_long); + fprintf (file_out, "\n%s\n", stripped_html); + xfree(stripped_html); + } + if (wpt->gc_data.hint) { + char *hint = NULL; + if ( encrypt ) + hint = rot13( wpt->gc_data.hint ); + else + hint = xstrdup( wpt->gc_data.hint ); + fprintf (file_out, "\nHint: %s\n", hint); + xfree( hint ); + } + } + else if (wpt->notes && (!wpt->description || strcmp(wpt->notes,wpt->description))) { + fprintf (file_out, "%s\n", wpt->notes); + } + + if ( includelogs && wpt->gpx_extras ) { + xml_tag *root = wpt->gpx_extras; + xml_tag *curlog = NULL; + xml_tag *logpart = NULL; + curlog = xml_findfirst( root, "groundspeak:log" ); + while ( curlog ) { + time_t logtime = 0; + struct tm *logtm = NULL; + fprintf( file_out, "\n" ); + + logpart = xml_findfirst( curlog, "groundspeak:type" ); + if ( logpart ) { + fprintf( file_out, "%s by ", logpart->cdata ); + } + + logpart = xml_findfirst( curlog, "groundspeak:finder" ); + if ( logpart ) { + fprintf( file_out, "%s on ", logpart->cdata ); + } + + logpart = xml_findfirst( curlog, "groundspeak:date" ); + if ( logpart ) { + logtime = xml_parse_time( logpart->cdata ); + logtm = localtime( &logtime ); + if ( logtm ) { + fprintf( file_out, + "%2.2d/%2.2d/%4.4d\n", + logtm->tm_mon+1, + logtm->tm_mday, + logtm->tm_year+1900 + ); + } + } + + logpart = xml_findfirst( curlog, "groundspeak:log_wpt" ); + if ( logpart ) { + char *coordstr = NULL; + float lat = 0; + int latdeg = 0; + float lon = 0; + int londeg = 0; + coordstr = xml_attribute( logpart, "lat" ); + if ( coordstr ) { + lat = atof( coordstr ); + } + coordstr = xml_attribute( logpart, "lon" ); + if ( coordstr ) { + lon = atof( coordstr ); + } + latdeg = abs(lat); + londeg = abs(lon); + + fprintf( file_out, + "%c %d %.3f' %c %d %.3f'\n", + + lat < 0 ? 'S' : 'N', latdeg, 60.0 * (fabs(lat) - latdeg), + lon < 0 ? 'W' : 'E', londeg, 60.0 * (fabs(lon) - londeg) + ); + } + + logpart = xml_findfirst( curlog, "groundspeak:text" ); + if ( logpart ) { + char *encstr = NULL; + char *s = NULL; + int encoded = 0; + encstr = xml_attribute( logpart, "encoded" ); + encoded = (encstr[0] != 'F'); + + if ( encrypt && encoded ) { + s = rot13( logpart->cdata ); + } + else { + s = xstrdup( logpart->cdata ); + } + + fprintf( file_out, "%s", s ); + xfree( s ); + } + + fprintf( file_out, "\n" ); + curlog = xml_findnext( root, curlog, "groundspeak:log" ); + } + } + if (! suppresssep) + fprintf(file_out, "-----------------------------------------------------------------------------\n"); + else + fprintf(file_out, "\n"); + + +} + +static void +data_write(void) +{ + if (! suppresssep) + fprintf(file_out, "-----------------------------------------------------------------------------\n"); + setshort_length(mkshort_handle, 6); + waypt_disp_all(text_disp); +} + + +ff_vecs_t text_vecs = { + ff_type_file, + NULL, + wr_init, + NULL, + wr_deinit, + NULL, + data_write, + NULL, + text_args +}; diff --git a/tiger.c b/tiger.c new file mode 100644 index 000000000..e0fdfd4f1 --- /dev/null +++ b/tiger.c @@ -0,0 +1,288 @@ +/* + Access to U.S. Census Bureau "tiger" format. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "csv_util.h" + +static FILE *file_in; +static FILE *file_out; +static void *mkshort_handle; +static void *mkshort_whandle; + +#define MYNAME "GPSUTIL" + +static double maxlat, maxlon, minlat, minlon; +int rec_cnt; +static char *nolabels = NULL; +static char *genurl = NULL; +static char *suppresswhite = NULL; +static char *iconismarker = NULL; +static char *snlen = NULL; + +static char *margin = NULL; +static char *xpixels = NULL; +static char *ypixels = NULL; +static char *oldthresh = NULL; +static char *oldmarker = NULL; +static char *newmarker = NULL; +static char *unfoundmarker = NULL; + +int scalev; +int short_length; +double thresh_days; + +/* + * The code bracketed by CLICKMAP is to generate clickable image maps + * for a web browser. It's functional, but is missing the math to do + * the projection transformations. Some trig geek can finish that. + */ +#if CLICKMAP +static FILE *linkf; +static char *clickmap = NULL; +#endif + + +static +arglist_t tiger_args[] = { + {"nolabels", &nolabels, "Suppress labels on generated pins.", + NULL, ARGTYPE_BOOL }, + {"genurl", &genurl, "Generate file with lat/lon for centering map.", + NULL, ARGTYPE_OUTFILE }, + {"margin", &margin, "Margin for map. Degrees or percentage.", + "15%", ARGTYPE_FLOAT}, + {"snlen", &snlen, "Max shortname length when used with -s.", + NULL, ARGTYPE_INT}, + {"oldthresh", &oldthresh, + "Days after which points are considered old.", + "14", ARGTYPE_INT}, + {"oldmarker", &oldmarker, "Marker type for old points.", + "redpin", ARGTYPE_STRING}, + {"newmarker", &newmarker, "Marker type for new points.", + "greenpin", ARGTYPE_STRING}, + {"suppresswhite", &suppresswhite, + "Suppress whitespace in generated shortnames", + NULL, ARGTYPE_BOOL }, + {"unfoundmarker", &unfoundmarker, "Marker type for unfound points.", + "bluepin", ARGTYPE_STRING}, + {"xpixels", &xpixels, "Width in pixels of map.", + "768", ARGTYPE_INT}, + {"ypixels", &ypixels, "Height in pixels of map.", + "768", ARGTYPE_INT}, + {"iconismarker", &iconismarker, + "The icon description is already the marker", NULL, + ARGTYPE_BOOL }, +#if CLICKMAP + {"clickmap", &clickmap, "Generate Clickable map web page.", + NULL, ARGTYPE_BOOL}, +#endif + {0, 0, 0, 0, 0} +}; + + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "r", MYNAME); + mkshort_handle = mkshort_new_handle(); +} + +static void +rd_deinit(void) +{ + fclose(file_in); + mkshort_del_handle(mkshort_handle); +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "w", MYNAME); + thresh_days = strtod(oldthresh, NULL); +} + +static void +wr_deinit(void) +{ + fclose(file_out); +} + +static void +data_read(void) +{ + double lat,lon; + char desc[100]; + char icon[100]; + char ibuf[1024]; + waypoint *wpt_tmp; + + while (fgets(ibuf, sizeof(ibuf), file_in)) { + if( sscanf(ibuf, "%lf,%lf:%100[^:]:%100[^\n]", + &lon, &lat, icon, desc)) { + wpt_tmp = xcalloc(sizeof (*wpt_tmp), 1); + + wpt_tmp->longitude = lon; + wpt_tmp->latitude = lat; + wpt_tmp->description = xstrdup(desc); + wpt_tmp->shortname = mkshort(mkshort_handle, desc); + + waypt_add(wpt_tmp); + } + } +} + +static void +tiger_disp(const waypoint *wpt) +{ + const char *pin; + double lat = wpt->latitude; + double lon = wpt->longitude; + + if (iconismarker) + pin = wpt->icon_descr ? wpt->icon_descr : ""; + else if (wpt->icon_descr && strstr(wpt->icon_descr, "-unfound")) + pin = unfoundmarker; + else if (wpt->creation_time > current_time() - 3600 * 24 * thresh_days) + pin = newmarker; + else + pin = oldmarker; + + if (genurl) { + if (lat > maxlat) maxlat = lat; + if (lon > maxlon) maxlon = lon; + if (lat < minlat) minlat = lat; + if (lon < minlon) minlon = lon; + } + + fprintf(file_out, "%f,%f:%s", lon, lat, pin); + if (!nolabels) { + char *desc = csv_stringclean(wpt->description, ":"); + char *adesc = str_utf8_to_ascii(desc); + if (global_opts.synthesize_shortnames) + adesc = mkshort(mkshort_whandle, adesc); + fprintf(file_out, ":%s", adesc); + xfree(desc); + xfree(adesc); + } + fprintf(file_out, "\n"); +} + +#if CLICKMAP +static void +map_plot(const waypoint *wpt) +{ + static int x,y; + + /* Replace with real math. */ + x+=10; + y+=10; + + fprintf(linkf, "\"%s\"\n",url, wpt->description); +} +#endif /* CLICKMAP */ + +static double +dscale(double distance) +{ + /* + * If we have any specified margin options factor those in now. + * A additional little boundary is helpful because Tiger always + * puts the pin above the actual coord and if we don't pad the + * top will be clipped. It also makes the maps more useful to + * have a little bit of context around the pins on the border. + */ + + if (strchr(margin, '%')) + return distance + strtod(margin, NULL) / 100.0 * distance; + else + return strtod(margin, NULL) + distance; +} + +static void +data_write(void) +{ + double latsz,lonsz; + maxlat = -9999.0; + maxlon = -9999.0; + minlat = 9999.0; + minlon = 9999.0; + rec_cnt = 0; + + if (snlen) + short_length = atoi(snlen); + else + short_length = 10; + mkshort_whandle = mkshort_new_handle(); + + if (suppresswhite) { + setshort_whitespace_ok(mkshort_whandle, 0); + } + + setshort_length(mkshort_whandle, short_length); + + fprintf(file_out, "#tms-marker\n"); + waypt_disp_all(tiger_disp); + + if (genurl) { + FILE *urlf; + + urlf = xfopen(genurl, "w", MYNAME); + latsz = fabs(maxlat - minlat); + lonsz = fabs(maxlon - minlon); + + /* + * Center the map along X and Y axis the midpoint of + * our min and max coords each way. + */ + fprintf(urlf, "lat=%f&lon=%f&ht=%f&wid=%f", + minlat + (latsz/2.0), + minlon + (lonsz/2.0), + dscale(latsz), + dscale(lonsz)); + + fprintf(urlf, "&iwd=%s&iht=%s", xpixels, ypixels); + fclose(urlf); +#if CLICKMAP + if (clickmap) { + linkf = xfopen(clickmap, "w", MY NAME); + fprintf(linkf, "\n"); + waypt_disp_all(map_plot); + fprintf(linkf, "\n"); + fclose(linkf); + linkf = NULL; + } +#endif + } + + mkshort_del_handle(mkshort_whandle); +} + + +ff_vecs_t tiger_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL, + tiger_args, +}; diff --git a/tmpro.c b/tmpro.c new file mode 100644 index 000000000..e9968814d --- /dev/null +++ b/tmpro.c @@ -0,0 +1,255 @@ +/* + ---------------------------------------------------------------------------------------- + TopoMapPro (.txt) + New Zealand Mapping Software + www.topomappro.com + (Tab Delimited text file) + + Based on gpsbabel .MXF format by Alex Mottram (geo_alexm at cox-internet.com) + Tweaked for TopoMapPro by Nick Heaphy (nick at automata dot co dot nz) + + Group sID sDescription fLat fLong fEasting fNorthing fAlt iColour iSymbol sHyperLink + 25 6 80 8 8 8 8 8 4 4 128 (lengths) + + Based on the specifications found in the TopoMapPro documentation available from website + ---------------------------------------------------------------------------------------- + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "csv_util.h" +#include + +#define MYNAME "TMPro" + +static FILE *file_in; +static FILE *file_out; +static void *mkshort_handle; + +static void +rd_init(const char *fname) +{ + file_in = xfopen(fname, "r", MYNAME); +} + +static void +rd_deinit(void) +{ + fclose(file_in); +} + +static void +wr_init(const char *fname) +{ + file_out = xfopen(fname, "w", MYNAME); +} + +static void +wr_deinit(void) +{ + fclose(file_out); +} + +static void +data_read(void) +{ + char buff[1024]; + char *s; + char *holder; + waypoint *wpt_tmp; + int i; + int linecount = 0; + + do { + linecount++; + memset(&buff, '\0', sizeof(buff)); + fgets(buff, sizeof(buff), file_in); + + /* skip the line if it contains "sHyperLink" as it is a header (I hope :) */ + if ((strlen(buff)) && (strstr(buff, "sHyperLink") == NULL)) { + + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + + /* data delimited by tabs, not enclosed in quotes. */ + s = buff; + s = csv_lineparse(s, "\t", "", linecount); + + i = 0; + while (s) { + switch (i) { + + /* Group sID sDescription fLat fLong fEasting fNorthing fAlt iColour iSymbol sHyperLink */ + /* 0 1 2 3 4 5 6 7 8 9 10 */ + + case 0: + /* ignore: group */ + break; + case 1: + wpt_tmp->shortname = csv_stringtrim(s, "", 0); + break; + case 2: + /* Description is not a TopoMapPro format requirement. + If we assign "" then .loc/.gpx will generate empty XML tags :( + */ + holder = csv_stringtrim(s, "", 0); + if (strlen(holder)) + wpt_tmp->description = holder; + break; + case 3: + wpt_tmp->latitude = atof(s); + break; + case 4: + wpt_tmp->longitude = atof(s); + break; + case 5: + /* ignore: NZMapGrid Easting */ + break; + case 6: + /* ignore: NZMapGrid Northing */ + break; + case 7: + wpt_tmp->altitude = atof(s); + break; + case 8: + /* ignore: color */ + break; + case 9: + /* ignore: symbol (non standard) */ + break; + case 10: + /* URL is not a TopoMapPro format requirement. + You can store file links etc, we will discard anything that is not http + (as URLs in TMPro must start "http:") as other GPS formats probably can't + use the TopoMapLinks links. + (plus discards length 0 strings (so no empty XML tags)) + */ + holder = csv_stringtrim(s, "", 0); + if (strstr(holder, "http:") != NULL) + wpt_tmp->url = holder; + break; + default: + /* whoa! nelly */ + warning(MYNAME ": Warning: data fields on line %d exceed specification.\n", + linecount); + break; + } + i++; + + s = csv_lineparse(NULL, "\t", "\"", linecount); + } + + if (i != 11) { + xfree(wpt_tmp); + warning(MYNAME ": WARNING - extracted %d fields from line %d. \nData on line ignored.\n", + i, linecount); + } else { + waypt_add(wpt_tmp); + } + + } else { + /* empty line */ + } + + } while (!feof(file_in)); +} + +static void +tmpro_waypt_pr(const waypoint * wpt) +{ + int icon = 1; /* default to "flag" */ + int colour = 255; /*default to red */ + char *shortname = NULL; + char *description = NULL; + + if ((! wpt->shortname) || (global_opts.synthesize_shortnames)) { + if (wpt->description) { + if (global_opts.synthesize_shortnames) + shortname = mkshort(mkshort_handle, wpt->description); + else + shortname = csv_stringclean(wpt->description, ",\""); + } else { + /* no description available */ + shortname = xstrdup(""); + } + } else{ + shortname = csv_stringclean(wpt->shortname, ",\""); + } + + if (! wpt->description) { + if (shortname) { + description = csv_stringclean(shortname, ",\""); + } else { + description = xstrdup(""); + } + } else{ + description = csv_stringclean(wpt->description, ",\""); + } + + /* Group sID sDescription fLat fLong fEasting fNorthing fAlt iColour iSymbol sHyperLink */ + /* 0 1 2 3 4 5 6 7 8 9 10 */ + /* Number of characters */ + /* 25 6 80 8 8 8 8 8 4 4 128 */ + + fprintf(file_out, "new\t%.6s\t%.80s\t%08.6f\t%08.6f\t\t\t%.2f\t%d\t%d\t%.128s\n", + shortname, + description, + wpt->latitude, + wpt->longitude, + wpt->altitude, + colour, + icon, + wpt->url + ); + + + if (description) + xfree(description); + if (shortname) + xfree(shortname); +} + +static void +data_write(void) +{ + /* Short names */ + if (global_opts.synthesize_shortnames) { + mkshort_handle = mkshort_new_handle(); + setshort_length(mkshort_handle, 6); + setshort_whitespace_ok(mkshort_handle, 0); + setshort_badchars(mkshort_handle, "\","); + } + + /* Write file header */ + fprintf(file_out, "Group\tsID\tsDescription\tfLat\tfLong\tfEasting\tfNorthing\tfAlt\tiColour\tiSymbol\tsHyperLink\n"); + + waypt_disp_all(tmpro_waypt_pr); + mkshort_del_handle(mkshort_handle); +} + +ff_vecs_t tmpro_vecs = { + ff_type_file, + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL +}; + diff --git a/tools/cleardebug b/tools/cleardebug new file mode 100644 index 000000000..1ee27e11a --- /dev/null +++ b/tools/cleardebug @@ -0,0 +1,5 @@ +#!/bin/sh + +rm /tmp/gpsbabel.debug +touch /tmp/gpsbabel.debug + diff --git a/tools/cvslog b/tools/cvslog new file mode 100644 index 000000000..9ec5899a0 --- /dev/null +++ b/tools/cvslog @@ -0,0 +1 @@ +# cvs log -b -N -d '>2003-09-22' | less +date diff --git a/tools/memdebug b/tools/memdebug new file mode 100644 index 000000000..3a50da20a --- /dev/null +++ b/tools/memdebug @@ -0,0 +1,71 @@ +#!/usr/bin/perl + +sub alloc { + my $addr = shift; + my $file = shift; + my $line = shift; + + if ( $arena{$addr} ) { + ($ofile,$oline) = @{$arena{$addr}}; + print( "duplicate allocation $addr at $file $line\n allocated at $ofile $oline\n" ); + } + $arena{$addr} = [$file,$line]; +} + +sub free { + my $addr = shift; + my $file = shift; + my $line = shift; + + if ( $arena{$addr} ) { + $freed{$addr} = [$arena{$addr}->[0], $arena{$addr}->[1], $file, $line]; + delete $arena{$addr}; + } + else { + if ($freed{$addr}) { + ($afile,$aline,$ffile,$fline) = @{$freed{$addr}}; + print( "double free $addr at $file $line\n allocated at $afile $aline\n last freed at $ffile $fline\n" ); + } + else { + print( "freeing unallocated $addr at $file $line\n" ); + } + } +} + +sub unfreed { + for $addr (keys %arena) { + ($file,$line)=@{$arena{$addr}}; + print( "unfreed $addr allocated at $file $line\n" ); + } + undef %arena; + undef %freed; +} + +open(FILE, ") { + chomp; + @args = split(', ',$_); + if ($args[0] eq 'malloc') { + &alloc($args[1], $args[3], $args[4]); + } + if ($args[0] eq 'calloc') { + &alloc($args[1], $args[4], $args[5]); + } + if ($args[0] eq 'strdup') { + &alloc($args[1], $args[3], $args[4]); + } + if ($args[0] eq 'realloc') { + &free($args[2], $args[4], $args[5]); + &alloc($args[1], $args[4], $args[5]); + } + if ($args[0] eq 'free') { + &free($args[1], $args[2], $args[3]); + } + if ($args[0] =~ m/^command/) { + &unfreed; + print "$args[0]\n"; + } +} +&unfreed; +close(FILE); diff --git a/tools/mkchanges b/tools/mkchanges new file mode 100644 index 000000000..ed3b9ec5f --- /dev/null +++ b/tools/mkchanges @@ -0,0 +1,15 @@ +cvsps $* | awk ' +/^Date:/ { + logt = ""; + gsub("/", "-"); + split($0, dte, " "); + + printf "\n%s", dte[2]; + printf "
" + } +/^Log:/ { gsub("^Log:", ""); inlog = 1 } +/^Members:/ {printf "%s", logt ; inlog = 0; } +{ if (inlog > 0) { logt = logt $0 ;} } +' | sort -rn | sed "s##\\ +<\/tr>#g" diff --git a/torture_test b/torture_test new file mode 100644 index 000000000..66095cf55 --- /dev/null +++ b/torture_test @@ -0,0 +1,27 @@ + +PNAME=${PNAME:-./gpsbabel} +DIFF=${DIFF:-diff} + +TMPDIR=/tmp/gpsbabel.$$ +mkdir -p $TMPDIR +trap "rm -fr $TMPDIR" 0 1 2 3 15 + +# +# This is nasty. If we have a dictionary handy, treat it as a list of +# waypoints and reduce all the names to eight characters. Fewer chars +# results in lost waypoints currently and that's a defect. +# +DICT=/usr/share/dict/words +if [ -f $DICT ]; +then + WORDS=`cat $DICT | wc -l` + SWORDS=`${PNAME} -i gpsdrive -f $DICT -o gpsdrive,snlen=8 -F /dev/fd/1 | + wc -l` + if [ $WORDS -ne $SWORDS ]; + then + echo "Shortname reduction failed." + exit 1 + fi +fi + +exit 0 diff --git a/tpg.c b/tpg.c new file mode 100644 index 000000000..d9eb11c7c --- /dev/null +++ b/tpg.c @@ -0,0 +1,365 @@ +/* + National Geographic Topo! Waypoint + Contributed to gpsbabel by Alex Mottram + + Copyright (C) 2002 Alex Mottram, geo_alexm at cox-internet.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include +#include "jeeps/gpsmath.h" /* for datum conversions */ + +#define MYNAME "TPG" + +#define MAXTPGSTRINGSIZE 256 +#define MAXTPGOUTPUTPINS 65535 + +static FILE *tpg_file_in; +static FILE *tpg_file_out; +static void *mkshort_handle; + +static unsigned int waypt_out_count; + +static int +tpg_fread(void *buff, size_t size, size_t members, FILE * fp) +{ + size_t br; + + br = fread(buff, size, members, fp); + + if (br != members) { + fatal(MYNAME ": requested to read %d bytes, read %d bytes.\n", members, br); + } + + return (br); +} + +static double +tpg_fread_double(FILE *fp) +{ + unsigned char buf[8]; + unsigned char sbuf[8]; + + tpg_fread(buf, 1, 8, fp); + le_read64(sbuf, buf); + return *(double *)sbuf; +} + +static void +tpg_fwrite_double(double x, FILE *fp) +{ + unsigned char *cptr = (unsigned char *)&x; + unsigned char cbuf[8]; + + le_read64(cbuf, cptr); + fwrite(cbuf, 8, 1, fp); +} + +static int +valid_tpg_header(char * header, int len) +{ + unsigned char header_bytes[] = { 0xFF, 0xFF, 0x01, 0x00, 0x0D, + 0x00, 0x43, 0x54, 0x6F, 0x70, + 0x6F, 0x57, 0x61, 0x79, 0x70, + 0x6F, 0x69, 0x6E, 0x74 }; + if (len != 19) { + return (-1); + } + + return memcmp(header_bytes, header, len); +} + +static void +tpg_rd_init(const char *fname) +{ + tpg_file_in = xfopen(fname, "rb", MYNAME); +} + +static void +tpg_rd_deinit(void) +{ + fclose(tpg_file_in); +} + +static void +tpg_wr_init(const char *fname) +{ + tpg_file_out = xfopen(fname, "wb", MYNAME); + mkshort_handle = mkshort_new_handle(); + waypt_out_count = 0; +} + +static void +tpg_wr_deinit(void) +{ + mkshort_del_handle(mkshort_handle); + fclose(tpg_file_out); +} + +static void +tpg_read(void) +{ + char buff[MAXTPGSTRINGSIZE + 1]; + waypoint *wpt_tmp; + double lat, lon, elev; + double amt; + int stringsize; + short int pointcount; + + tpg_fread(&buff[0], 2, 1, tpg_file_in); + + pointcount = le_read16(&buff[0]); + + /* the rest of the header */ + tpg_fread(&buff[0], 19, 1, tpg_file_in); + + if (valid_tpg_header(buff, 19) != 0) { + fatal(MYNAME ": input file does not appear to be a valid .TPG file.\n"); + } + + + while (pointcount--) { + wpt_tmp = xcalloc(sizeof(*wpt_tmp),1); + + /* 1 bytes at start of record - string size for shortname */ + tpg_fread(&buff[0], 1, 1, tpg_file_in); + + stringsize = buff[0]; + + tpg_fread(&buff[0], stringsize, 1, tpg_file_in); + + buff[stringsize] = '\0'; + + wpt_tmp->shortname = xstrdup(buff); + + /* for some very odd reason, signs on longitude are swapped */ + /* coordinates are in NAD27/CONUS datum */ + + /* 8 bytes - longitude, sign swapped */ + lon = tpg_fread_double(tpg_file_in); + + /* 8 bytes - latitude */ + lat = tpg_fread_double(tpg_file_in); + + /* swap sign before we do datum conversions */ + lon *= -1.0; + + /* 2 bytes - elevation in feet */ + tpg_fread(&buff[0], 2, 1, tpg_file_in); + elev = (le_read16(&buff[0]) * .3048); /* feets to meters */ + + /* convert incoming NAD27/CONUS coordinates to WGS84 */ + GPS_Math_Known_Datum_To_WGS84_M( + lat, + lon, + 0.0, + &wpt_tmp->latitude, + &wpt_tmp->longitude, + &amt, + 78); + + wpt_tmp->altitude = elev; + + + /* 4 bytes? */ + tpg_fread(&buff[0], 4, 1, tpg_file_in); + + /* 1 bytes - string size for description */ + tpg_fread(&buff[0], 1, 1, tpg_file_in); + + stringsize = buff[0]; + + tpg_fread(&buff[0], stringsize, 1, tpg_file_in); + buff[stringsize] = '\0'; + + wpt_tmp->description = xstrdup(buff); + + /* 2 bytes */ + tpg_fread(&buff[0], 2, 1, tpg_file_in); + + waypt_add(wpt_tmp); + } +} + +static void +tpg_waypt_pr(const waypoint *wpt) +{ + double lon, lat; + double amt; + short int elev; + char tbuf[64]; + char c,ocount; + char *shortname; + char *description; + int i; + + /* these unknown 4 are probably point properties (color, icon, etc..) */ + unsigned char unknown4[] = { 0x78, 0x56, 0x34, 0x12 }; + + /* these 2 appear to be constant across test files */ + unsigned char unknown2[] = { 0x01, 0x80 }; + + /* our personal waypoint counter */ + waypt_out_count++; + + /* this output format pretty much requires a description + * and a shortname + */ + + if ((! wpt->shortname) || (global_opts.synthesize_shortnames)) { + if (wpt->description) { + if (global_opts.synthesize_shortnames) + shortname = mkshort(mkshort_handle, wpt->description); + else + shortname = xstrdup(wpt->description); + } else { + /* no description available */ + shortname = xstrdup(""); + } + } else{ + shortname = xstrdup(wpt->shortname); + } + + if (! wpt->description) { + if (shortname) { + description = xstrdup(shortname); + } else { + description = xstrdup(""); + } + } else{ + description = xstrdup(wpt->description); + } + + /* convert lat/long to NAD27/CONUS datum */ + GPS_Math_WGS84_To_Known_Datum_M( + wpt->latitude, + wpt->longitude, + 0.0, + &lat, + &lon, + &amt, + 78); + + + /* swap the sign back *after* the datum conversion */ + lon *= -1.0; + + /* convert meters back to feets */ + elev = (short int) (wpt->altitude * 3.2808); + + /* 1 bytes stringsize for shortname */ + c = strlen(shortname); + ocount = 0; + /* + * It's reported the only legal characters are upper case + * A-Z and 0-9. Wow. We have to make two passes: one to + * count and one to output. + */ + for (i = 0; i < c; i++) { + char oc = toupper(shortname[i]); + if (isalnum(oc) || oc == ' ') { + ocount++; + } + } + + fwrite(&ocount, 1, 1, tpg_file_out); + + for (i = 0; i < c; i++) { + char oc = toupper(shortname[i]); + if (isalnum(oc) || oc == ' ') { + fputc(oc, tpg_file_out); + } + } + + /* 8 bytes - longitude */ + tpg_fwrite_double(lon, tpg_file_out); + + /* 8 bytes - latitude */ + tpg_fwrite_double(lat, tpg_file_out); + + /* 2 bytes - elevation_feet */ + fwrite(&elev, 1, 2, tpg_file_out); + + /* 4 unknown bytes */ + memset(tbuf, '\0', sizeof(tbuf)); + fwrite(unknown4, 1, 4, tpg_file_out); + + /* 1 bytes stringsize for description */ + c = strlen(description); + fwrite(&c, 1, 1, tpg_file_out); + + /* description */ + fwrite(description, 1, c, tpg_file_out); + + /* and finally 2 unknown bytes */ + + if (waypt_out_count == waypt_count()) { + /* last point gets 0x0000 instead of 0x0180 */ + memset(tbuf, '\0', sizeof(tbuf)); + fwrite(tbuf, 1, 2, tpg_file_out); + } else { + fwrite(unknown2, 1, 2, tpg_file_out); + } + + xfree(shortname); + xfree(description); +} + +static void +tpg_write(void) +{ + int s; + unsigned char uc[2]; + unsigned char header_bytes[] = { 0xFF, 0xFF, 0x01, 0x00, 0x0D, + 0x00, 0x43, 0x54, 0x6F, 0x70, + 0x6F, 0x57, 0x61, 0x79, 0x70, + 0x6F, 0x69, 0x6E, 0x74 }; + + s = waypt_count(); + + if (global_opts.synthesize_shortnames) { + setshort_length(mkshort_handle, 32); + setshort_whitespace_ok(mkshort_handle, 1); + setshort_mustupper(mkshort_handle, 1); + } + + if (s > MAXTPGOUTPUTPINS) { + fatal(MYNAME ": attempt to output too many points (%d). The max is %d. Sorry.\n", s, MAXTPGOUTPUTPINS); + } + + le_write16(uc, s); + + /* write the waypoint count */ + fwrite(uc, 1, 2, tpg_file_out); + + /* write the rest of the header */ + fwrite(header_bytes, 1, 19, tpg_file_out); + + waypt_disp_all(tpg_waypt_pr); +} + +ff_vecs_t tpg_vecs = { + ff_type_file, + tpg_rd_init, + tpg_wr_init, + tpg_rd_deinit, + tpg_wr_deinit, + tpg_read, + tpg_write, + NULL +}; diff --git a/util.c b/util.c new file mode 100644 index 000000000..975b7598f --- /dev/null +++ b/util.c @@ -0,0 +1,1156 @@ +/* + Misc utilities. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include +#include +#include +#include + +static int i_am_little_endian = -1; +static int doswap(void); + +#ifdef DEBUG_MEM +#define DEBUG_FILENAME "/tmp/gpsbabel.debug" + +static FILE *debug_mem_file = NULL; +void +debug_mem_open() +{ + debug_mem_file = xfopen( DEBUG_FILENAME, "a", "debug" ); +} + +void +debug_mem_output(char *format, ...) +{ + va_list args; + va_start( args, format ); + if ( debug_mem_file ) { + vfprintf( debug_mem_file, format, args ); + fflush( debug_mem_file ); + } + va_end( args ); +} + +void +debug_mem_close() +{ + if ( debug_mem_file ) { + fclose(debug_mem_file); + } + debug_mem_file = NULL; +} +#endif + +void * +#ifdef DEBUG_MEM +XMALLOC(size_t size, DEBUG_PARAMS) +#else +xmalloc(size_t size) +#endif +{ + void *obj = malloc(size); + +#ifdef DEBUG_MEM + debug_mem_output( "malloc, %x, %d, %s, %d\n", + obj, size, file, line ); +#endif + if (!obj) { + fatal("gpsbabel: Unable to allocate %d bytes of memory.\n", size); + } + + return obj; +} + +void * +#ifdef DEBUG_MEM +XCALLOC(size_t nmemb, size_t size, DEBUG_PARAMS) +#else +xcalloc(size_t nmemb, size_t size) +#endif +{ + void *obj = calloc(nmemb, size); +#ifdef DEBUG_MEM + debug_mem_output( "calloc, %x, %d, %d, %s, %d\n", + obj, nmemb, size, file, line ); +#endif + + if (!obj) { + fatal("gpsbabel: Unable to allocate %d bytes of memory.\n", size); + } + + return obj; +} + +void +#ifdef DEBUG_MEM +XFREE( void *mem, DEBUG_PARAMS ) +#else +xfree( void *mem ) +#endif +{ + free(mem); +#ifdef DEBUG_MEM + debug_mem_output( "free, %x, %s, %d\n", + mem, file, line ); +#endif +} + +char * +#ifdef DEBUG_MEM +XSTRDUP(const char *s, DEBUG_PARAMS ) +#else +xstrdup(const char *s) +#endif +{ + char *o = strdup(s); +#ifdef DEBUG_MEM + debug_mem_output( "strdup, %x, %x, %s, %d\n", + o, s, file, line ); +#endif + + if (!o) { + fatal("gpsbabel: Unable to allocate %d bytes of memory.\n", strlen(s)); + } + + return o; +} + +/* + * Duplicate at most sz bytes in str. + */ +char * +#ifdef DEBUG_MEM +XSTRNDUP(const char *str, size_t sz, DEBUG_PARAMS ) +#else +xstrndup(const char *str, size_t sz) +#endif +{ + size_t newlen; + char *newstr; + + newlen = strlen(str); + if (newlen > sz) { + newlen = sz; + } + + newstr = (char *) xmalloc(newlen + 1); + memcpy(newstr, str, newlen); + newstr[newlen] = 0; + + return newstr; +} + +/* + * Lazily trim whitespace (though not from allocated version) + * while copying. + */ +char * +#ifdef DEBUG_MEM +XSTRNDUPT(const char *str, size_t sz, DEBUG_PARAMS ) +#else +xstrndupt(const char *str, size_t sz) +#endif +{ + size_t newlen; + char *newstr; + + newlen = strlen(str); + if (newlen > sz) { + newlen = sz; + } + + newstr = (char *) xmalloc(newlen + 1); + memcpy(newstr, str, newlen); + newstr[newlen] = '\0'; + rtrim(newstr); + + return newstr; +} + +void * +#ifdef DEBUG_MEM +XREALLOC(void *p, size_t s, DEBUG_PARAMS ) +#else +xrealloc(void *p, size_t s) +#endif +{ + char *o = (char *) realloc(p,s); +#ifdef DEBUG_MEM + debug_mem_output( "realloc, %x, %x, %x, %s, %d\n", + o, p, s, file, line ); +#endif + + if (!o) { + fatal("gpsbabel: Unable to realloc %d bytes of memory.\n", s); + } + + return o; +} + +/* +* For an allocated string, realloc it and append 's' +*/ +char * +#ifdef DEBUG_MEM +XSTRAPPEND(char *src, const char *newd, DEBUG_PARAMS) +#else +xstrappend(char *src, const char *newd) +#endif +{ + size_t newsz; + + if (!src) { + return xxstrdup(newd, file, line); + } + + newsz = strlen(src) + strlen(newd) + 1; + src = xxrealloc(src, newsz, file, line); + strcat(src, newd); + + return src; +} + +/* + * Wrapper for open that honours - for stdin, stdout, unifies error text. + */ +FILE * +xfopen(const char *fname, const char *type, const char *errtxt) +{ + FILE *f; + int am_writing = strchr(type, 'w') != NULL; + + if (fname == NULL) { + fatal("%s must have a filename specified for %s.\n", + errtxt, am_writing ? "write" : "read"); + } + + if (0 == strcmp(fname, "-")) + return am_writing ? stdout : stdin; + f = fopen(fname, type); + if (NULL == f) { + fatal("%s cannot open '%s' for %s. Error was '%s'.\n", + errtxt, fname, + am_writing ? "write" : "read", + strerror(errno)); + } + return f; +} + +void +xfprintf(const char *errtxt, FILE *stream, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + if (vfprintf(stream, format, ap) < 0) { + fatal("%s writing output file. Error was '%s'.\n", + errtxt, strerror(errno)); + } + va_end(ap); +} + +void +xfputs(const char *errtxt, const char *s, FILE *stream) +{ + if (fputs(s, stream) < 0) { + fatal("%s Writing output file. Error was '%s'.\n", + errtxt, strerror(errno)); + } +} + +/* + * Duplicate a pascal string into a normal C string. + */ +char * +pstrdup(char *src) +{ + int len = src[0]; + char *obuf = xmalloc(len + 1); + + memcpy(obuf, src + 1, len); + obuf[len] = 0; + + return obuf; +} + +void +rtrim(char *s) +{ + char *t = s; + + if (!s || !*s) { + return; + } + + while (*s) { + s++; + } + + s--; + while ((s >= t) && isspace (*s)) { + *s = 0; + s--; + } +} + +/* + * Like strcmp, but case insensitive. Like Berkeley's strcasecmp. + */ + +int +case_ignore_strcmp(const char *s1, const char *s2) +{ + for(;toupper(*s1) == toupper(*s2); ++ s1, ++s2) { + if (*s1 == 0) + return 0; + } + return (toupper(*s1) < toupper(*s2)) ? -1 : +1; + +} + +void +printposn(const double c, int is_lat) +{ + char d; + if (is_lat) { + if (c < 0) d = 'S'; else d = 'N'; + } else { + if (c < 0) d = 'W'; else d = 'E'; + } + printf("%f%c ", fabs(c), d); +} + +void +fatal(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +void +warning(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +/* + * Read 4 bytes in big-endian. Return as "int" in native endianness. + */ +signed int +be_read32(void *p) +{ + unsigned char *i = (unsigned char *) p; + return i[0] << 24 | i[1] << 16 | i[2] << 8 | i[3]; +} + +signed int +be_read16(void *p) +{ + unsigned char *i = (unsigned char *) p; + return i[0] << 8 | i[1]; +} + +void +be_write16(void *addr, unsigned value) +{ + unsigned char *p = addr; + p[0] = value >> 8; + p[1] = value; + +} + +void +be_write32(void *pp, unsigned i) +{ + char *p = (char *)pp; + + p[0] = (i >> 24) & 0xff; + p[1] = (i >> 16) & 0xff; + p[2] = (i >> 8) & 0xff; + p[3] = i & 0xff; +} + +signed int +le_read16(void *addr) +{ + unsigned char *p = addr; + return p[0] | (p[1] << 8); +} + +signed int +le_read32(void *addr) +{ + unsigned char *p = addr; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + +/* + * Read a little-endian 64-bit value from 'src' and return it in 'dest' + * in host endianness. + */ +void +le_read64(void *dest, const void *src) +{ + char *cdest = dest; + const char *csrc = src; + + doswap(); /* make sure i_am_little_endian is initialized */ + + if (i_am_little_endian) { + memcpy(dest, src, 8); + } else { + int i; + for (i = 0; i < 8; i++) { + cdest[i] = csrc[7-i]; + } + } +} + +void +le_write16(void *addr, unsigned value) +{ + unsigned char *p = addr; + p[0] = value; + p[1] = value >> 8; + +} + +void +le_write32(void *addr, unsigned value) +{ + unsigned char *p = addr; + p[0] = value; + p[1] = value >> 8; + p[2] = value >> 16; + p[3] = value >> 24; +} + +signed int +si_round( double d ) +{ + if ( d < 0 ) { + return (signed int)(d-0.5); + } + else { + return (signed int)(d+0.5); + } +} + +/* + * Return a time_t suitable for adding to a time_t that is in GMT to + * make it a local time. + */ +signed int +get_tz_offset(void) +{ + time_t now = current_time(); + time_t later = mktime(gmtime(&now)); + + if (later == -1) { + return 0; + } else { + return (signed int) difftime(now, later); + } +} + +/* + * A wrapper for time(2) that allows us to "freeze" time for testing. + */ +time_t +current_time(void) +{ + static char *frozen; + + if (getenv("GPSBABEL_FREEZE_TIME")) { + return 0; + } + + return time(NULL); +} + +/* + * Return the (zero based) month number of the year or -1 for failure. + */ +signed int +month_lookup(const char *m) +{ + static const char *months[] = { + "JAN", "FEB", "MAR", "APR", "MAY", "JUN", + "JUL", "AUG", "SEP", "OCT", "NOV", "DEC", NULL }; + const char **mp; + + for (mp = months; *mp; mp++) { + if (0 == case_ignore_strcmp(*mp, m)) + return mp - months; + } + return -1; +} + +/* + * Return a pointer to a constant string that is suitable for icon lookup + * based on geocache attributes. The strings used are those present in + * a GPX file from geocaching.com. Thus we sort of make all the other + * formats do lookups based on these strings. + */ +const char * +get_cache_icon(const waypoint *waypointp) +{ + if (global_opts.no_smart_icons) + return NULL; + + /* + * For icons, type overwrites container. So a multi-micro will + * get the icons for "multi". + */ + switch (waypointp->gc_data.type) { + case gt_virtual: + return "Virtual cache"; + case gt_multi: + return "Multi-Cache"; + case gt_event: + return "Event Cache"; + case gt_suprise: + return "Unknown Cache"; + case gt_webcam: + return "Webcam Cache"; + default: + break; + } + switch (waypointp->gc_data.container) { + case gc_micro: + return "Micro-Cache"; + break; + default: + break; + } + return NULL; +} + +static int doswap() +{ + if (i_am_little_endian < 0) + { + /* On Intel, Vax and MIPs little endian, -1.0 maps to the bytes + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f and on Motorola, + SPARC, ARM, and PowerPC, it maps to + 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00. + */ + double d = 1.0; + char c[8]; + memcpy(c, &d, 8); + i_am_little_endian = (c[0] == 0); + } + return i_am_little_endian; +} + +double +pdb_read_double(void* ptr) +{ + double ret; + char r[8]; + int i; + doswap(); /* make sure i_am_little_endian is initialized */ + for (i = 0; i < 8; i++) + { + int j = (i_am_little_endian)?(7-i):i; + r[i] = ((char*)ptr)[j]; + } + memcpy(&ret, r, 8); + return ret; +} + +void +pdb_write_double(void* ptr, double d) +{ + char r[8]; + int i; + char *optr = ptr; + + memcpy(r, &d, 8); + doswap(); /* make sure i_am_little_endian is initialized */ + for (i = 0; i < 8; i++) + { + int j = (i_am_little_endian)?(7-i):i; + *optr++ = r[j]; + } + return; +} + +/* Magellan and PCX formats use this DDMM.mm format */ +double ddmm2degrees(double pcx_val) { + double minutes; + signed int deg; + deg = (signed int) (pcx_val / 100.0); + minutes = (((pcx_val / 100.0) - deg) * 100.0) / 60.0; + return (double) deg + minutes; +} + +double degrees2ddmm(double deg_val) { + signed int deg; + deg = (signed int) deg_val; + return (double) (deg * 100.0) + ((deg_val - deg) * 60.0); +} + +/* + * replace a single occurrence of "search" in "s" with "replace". + * Returns an allocated copy if substitution was made, otherwise returns NULL. + * Doesn't try to make an optimally sized dest buffer. + */ +char * +strsub(char *s, char *search, char *replace) +{ + char *p; + int len = strlen(s); + int slen = strlen(search); + int rlen = strlen(replace); + char *d; + + p = strstr(s, search); + if (!slen || !p) { + return NULL; + } + + d = xmalloc(len + rlen); + + /* Copy first part */ + len = p - s; + memcpy(d, s, len); + d[len] = 0; + + /* Copy replacement */ + strcat(d, replace); + + /* Copy last part */ + strcat(d, p + slen); + return d; +} + +char * +rot13( const char *s ) +{ + char *result = xstrdup( s ); + char *cur = result; + int flip = 1; + while (cur && *cur ) { + if ( flip ) { + if (*cur == '[') flip = 0; + else if ( *cur >= 'A' && *cur <= 'Z' ) { + *cur = 'A' + ((*cur-'A')+13)%26; + } + else if ( *cur >= 'a' && *cur <= 'z' ) { + *cur = 'a' + ((*cur-'a')+13)%26; + } + } + else if ( *cur == ']' ) flip = 1; + cur++; + } + return result; +} + +void utf8_to_int( const char *cp, int *bytes, int *value ) +{ + if ( (*cp & 0xe0) == 0xc0 ) { + if ( (*(cp+1) & 0xc0) != 0x80 ) goto dodefault; + *bytes = 2; + *value = ((*cp & 0x1f) << 6) | + (*(cp+1) & 0x3f); + } + else if ( (*cp & 0xf0) == 0xe0 ) { + if ( (*(cp+1) & 0xc0) != 0x80 ) goto dodefault; + if ( (*(cp+2) & 0xc0) != 0x80 ) goto dodefault; + *bytes = 3; + *value = ((*cp & 0x0f) << 12) | + ((*(cp+1) & 0x3f) << 6) | + (*(cp+2) & 0x3f); + } + else if ( (*cp & 0xf8) == 0xf0 ) { + if ( (*(cp+1) & 0xc0) != 0x80 ) goto dodefault; + if ( (*(cp+2) & 0xc0) != 0x80 ) goto dodefault; + if ( (*(cp+3) & 0xc0) != 0x80 ) goto dodefault; + *bytes = 4; + *value = ((*cp & 0x07) << 18) | + ((*(cp+1) & 0x3f) << 12) | + ((*(cp+2) & 0x3f) << 6) | + (*(cp+3) & 0x3f); + } + else if ( (*cp & 0xfc) == 0xf8 ) { + if ( (*(cp+1) & 0xc0) != 0x80 ) goto dodefault; + if ( (*(cp+2) & 0xc0) != 0x80 ) goto dodefault; + if ( (*(cp+3) & 0xc0) != 0x80 ) goto dodefault; + if ( (*(cp+4) & 0xc0) != 0x80 ) goto dodefault; + *bytes = 5; + *value = ((*cp & 0x03) << 24) | + ((*(cp+1) & 0x3f) << 18) | + ((*(cp+2) & 0x3f) << 12) | + ((*(cp+3) & 0x3f) << 6) | + (*(cp+4) & 0x3f); + } + else if ( (*cp & 0xfe) == 0xfc ) { + if ( (*(cp+1) & 0xc0) != 0x80 ) goto dodefault; + if ( (*(cp+2) & 0xc0) != 0x80 ) goto dodefault; + if ( (*(cp+3) & 0xc0) != 0x80 ) goto dodefault; + if ( (*(cp+4) & 0xc0) != 0x80 ) goto dodefault; + if ( (*(cp+5) & 0xc0) != 0x80 ) goto dodefault; + *bytes = 6; + *value = ((*cp & 0x01) << 30) | + ((*(cp+1) & 0x3f) << 24) | + ((*(cp+2) & 0x3f) << 18) | + ((*(cp+3) & 0x3f) << 12) | + ((*(cp+4) & 0x3f) << 6) | + (*(cp+5) & 0x3f); + } + else { +dodefault: + *bytes = 1; + *value = (unsigned char)*cp; + } +} + +char * str_utf8_to_cp1252( const char * str ) +{ + char *result = xstrdup( str ); + char *cur = result; + + while ( cur && *cur ) { + if ( *cur & 0x80 ) { + int bytes; + int value; + utf8_to_int( cur, &bytes, &value ); + if ( value > 0xff ) { + switch (value) { + case 0x20AC: value = 0x80; break; + case 0x201A: value = 0x82; break; + case 0x0192: value = 0x83; break; + case 0x201E: value = 0x84; break; + case 0x2026: value = 0x85; break; + case 0x2020: value = 0x86; break; + case 0x2021: value = 0x87; break; + case 0x02C6: value = 0x88; break; + case 0x2030: value = 0x89; break; + case 0x0160: value = 0x8A; break; + case 0x2039: value = 0x8B; break; + case 0x0152: value = 0x8C; break; + case 0x017D: value = 0x8E; break; + case 0x2018: value = 0x91; break; + case 0x2019: value = 0x92; break; + case 0x201C: value = 0x93; break; + case 0x201D: value = 0x94; break; + case 0x2022: value = 0x95; break; + case 0x2013: value = 0x96; break; + case 0x2014: value = 0x97; break; + case 0x02DC: value = 0x98; break; + case 0x2122: value = 0x99; break; + case 0x0161: value = 0x9A; break; + case 0x203A: value = 0x9B; break; + case 0x0153: value = 0x9C; break; + case 0x017E: value = 0x9E; break; + case 0x0178: value = 0x9F; break; + /* default is the generic "currency */ + /* sign" because question marks */ + /* just look stupid. */ + default: value = 0xA4; break; + } + } + *cur = (char)value; + strcpy( cur+1, cur+bytes ); + } + cur++; + } + return result; +} + +char * str_utf8_to_ascii( const char * str ) +{ + char *result; + char *cur; + + if (!str) return NULL; + + result = xstrdup( str ); + cur = result; + + while ( cur && *cur ) { + if ( *cur & 0x80 ) { + int bytes; + int value; + char *strvalue = NULL; + utf8_to_int( cur, &bytes, &value ); + switch (value) { + case 0x2026: strvalue = "..."; break; + case 0x201c: value = '\"'; break; + case 0x201d: value = '\"'; break; + case 0xb4: + case 0x2018: value = '`'; break; + case 0x2019: value = '\''; break; + + case 0xf2: + case 0xf3: + case 0xf4: + case 0xf5: + case 0xf6: value = 'o'; break; + + case 0xe0: + case 0xe1: + case 0xe2: + case 0xe3: + case 0xe4: + case 0xe5: value = 'a'; break; + + case 0xe8: + case 0xe9: + case 0xea: + case 0xeb: value = 'e'; break; + + case 0xc0: + case 0xc1: + case 0xc2: + case 0xc3: + case 0xc4: + case 0xc5: value = 'A'; break; + + case 0xf8: value = '0'; break; + default: value='?'; break;; + } + if (strvalue) { + memcpy(cur, strvalue, bytes); + cur += bytes - 1; + } else { + *cur = (char)value; + strcpy( cur+1, cur+bytes ); + } + } + cur++; + } + return result; +} + +/* + * Get rid of potentially nasty HTML that would influence another record + * that includes; + * - to stop backgrounds from being loaded + * and - stop processing altogether + * - stop overriding styles for everything + */ +char * +strip_nastyhtml(const char * in) +{ + char *returnstr, *sp; + char *lcstr, *lcp; + int i; + + sp = returnstr = xstrdup(in); + lcp = lcstr = xstrdup(in); + + while (*lcp) { + *lcp = tolower(*lcp); + lcp++; + } + while (lcp = strstr(lcstr, "")) { + sp = returnstr + (lcp - lcstr) ; /* becomes --> */ + *sp++ = ' '; *sp++ = ' '; *sp++ = ' '; *sp++ = ' '; *sp++ = ' '; *sp++ = '-'; *sp++ = '-'; + *lcp = '*'; /* so we wont find it again */ + } + while (lcp = strstr(lcstr, "utfstring; + char tag[8]; + short int taglen; + + if (!in->is_html) + return in->utfstring; + /* + * We only shorten, so just dupe the input buf for space. + */ + + outstring = out = xstrdup(in->utfstring); + + tag[0] = 0; + while (*instr) { + if ((*instr == '<') || (*instr == '&')) { + tag[0] = *instr; + taglen = 0; + } + + if (! tag[0]) { + if (*instr != '\n') + *out++ = *instr; + } + else { + if (taglen < (sizeof(tag)-1)) { + tag[taglen++] = tolower(*instr); + tag[taglen] = 0; + } + } + + if ( ((tag[0] == '<') && (*instr == '>')) || + ((tag[0] == '&') && (*instr == ';')) ) { + if (! strcmp(tag,"&")) + *out++ = '&'; + else if (! strcmp (tag, "<")) + *out++ = '<'; + else if (! strcmp (tag, ">")) + *out++ = '>'; + else if (! strcmp (tag, """)) + *out++ = '"'; + else if (! strcmp (tag, " ")) + *out++ = ' '; + else if (! strcmp (tag, "°")) { + *out++ = 'd'; *out++ = 'e'; *out++ = 'g'; + } + else if ((tag[0]=='<') && (tag[1]=='p')) + *out++ = '\n'; + else if ((tag[0]=='<') && (tag[1]=='b') && (tag[2]=='r')) + *out++ = '\n'; + else if ((tag[0]=='<') && (tag[1]=='/') && (tag[2]=='t') && (tag[3]=='r')) + *out++ = '\n'; + else if ((tag[0]=='<') && (tag[1]=='/') && (tag[2]=='t') && (tag[3]=='d')) + *out++ = ' '; + else if ((tag[0]=='<') && (tag[1]=='i') && (tag[2]=='m') && (tag[3]=='g')) { + *out++ = '['; *out++ = 'I'; *out++ = 'M'; *out++ = 'G'; *out++ = ']'; + } + + tag[0] = 0; + } + *instr++; + } + *out++ = 0; + return (outstring); +} + +typedef struct { + const char * text; + const char * entity; + int not_html; +} entity_types; + +static +entity_types stdentities[] = { + { "&", "&", 0 }, + { "'", "'", 1 }, + { "<", "<", 0 }, + { ">", ">", 0 }, + { "\"", """, 0 }, + { NULL, NULL, 0 } +}; + +static +char * +entitize(const char * str, int is_html) +{ + int elen, ecount, nsecount; + entity_types *ep; + const char * cp; + char * p, * tmp, * xstr; + + char tmpsub[20]; + int bytes = 0; + int value = 0; + ep = stdentities; + elen = ecount = nsecount = 0; + + /* figure # of entity replacements and additional size. */ + while (ep->text) { + cp = str; + while ((cp = strstr(cp, ep->text)) != NULL) { + elen += strlen(ep->entity) - strlen(ep->text); + ecount++; + cp += strlen(ep->text); + } + ep++; + } + + /* figure the same for other than standard entities (i.e. anything + * that isn't in the range U+0000 to U+007F */ + for ( cp = str; *cp; cp++ ) { + if ( *cp & 0x80 ) { + + utf8_to_int( cp, &bytes, &value ); + cp += bytes-1; + elen += sprintf( tmpsub, "&#x%x;", value ) - bytes; + nsecount++; + } + } + + /* enough space for the whole string plus entity replacements, if any */ + tmp = xcalloc((strlen(str) + elen + 1), 1); + strcpy(tmp, str); + + /* no entity replacements */ + if (ecount == 0 && nsecount == 0) + return (tmp); + + if ( ecount != 0 ) { + for (ep = stdentities; ep->text; ep++) { + p = tmp; + if (is_html && ep->not_html) { + continue; + } + while ((p = strstr(p, ep->text)) != NULL) { + elen = strlen(ep->entity); + + xstr = xstrdup(p + strlen(ep->text)); + + strcpy(p, ep->entity); + strcpy(p + elen, xstr); + + xfree(xstr); + + p += elen; + } + } + } + + if ( nsecount != 0 ) { + p = tmp; + while (*p) { + if ( *p & 0x80 ) { + utf8_to_int( p, &bytes, &value ); + if ( p[bytes] ) { + xstr = xstrdup( p + bytes ); + } + else { + xstr = NULL; + } + sprintf( p, "&#x%x;", value ); + p = p+strlen(p); + if ( xstr ) { + strcpy( p, xstr ); + xfree(xstr); + } + } + else { + p++; + } + } + } + return (tmp); +} + +/* + * Public callers for the above to hide the absence of &apos from HTML + */ + +char * xml_entitize(const char * str) +{ + return entitize(str, 0); +} + +char * html_entitize(const char * str) +{ + return entitize(str, 1); +} + +/* + * xml_tag utilities + */ + +xml_tag *xml_next( xml_tag *root, xml_tag *cur ) +{ + if ( cur->child ) { + cur = cur->child; + } + else if ( cur->sibling ) { + cur = cur->sibling; + } + else { + cur = cur->parent; + if ( cur == root ) { + cur = NULL; + } + if ( cur ) { + cur = cur->sibling; + } + } + return cur; +} + +xml_tag *xml_findnext( xml_tag *root, xml_tag *cur, char *tagname ) +{ + xml_tag *result = cur; + do { + result = xml_next( root, result ); + } while ( result && case_ignore_strcmp( result->tagname, tagname )); + return result; +} + +xml_tag *xml_findfirst( xml_tag *root, char *tagname ) +{ + return xml_findnext( root, root, tagname ); +} + +char *xml_attribute( xml_tag *tag, char *attrname ) +{ + char *result = NULL; + if ( tag->attributes ) { + char **attr = tag->attributes; + while ( attr && *attr ) { + if ( 0 == case_ignore_strcmp( *attr, attrname )) { + result = attr[1]; + break; + } + attr+=2; + } + } + return result; +} diff --git a/util_crc.c b/util_crc.c new file mode 100644 index 000000000..390e66a77 --- /dev/null +++ b/util_crc.c @@ -0,0 +1,81 @@ +/* + Compute CRC32's. + + Copyright (C) 2002, 2003, 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +static unsigned long crc32_table[256] = +{ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +unsigned long +get_crc32(const void * data, int datalen) +{ + unsigned long crc = 0xFFFFFFFF; + const unsigned char * cp = (unsigned char *)data; + + while (cp < ((unsigned char *)data + datalen)) { + crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32_table[(crc ^ *cp) &0xFF]; + cp++; + } + + return (crc ^ 0xFFFFFFFF); +} diff --git a/vecs.c b/vecs.c new file mode 100644 index 000000000..855451091 --- /dev/null +++ b/vecs.c @@ -0,0 +1,595 @@ +/* + Describe vectors containing file operations. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include "defs.h" +#include "csv_util.h" + +typedef struct { + ff_vecs_t *vec; + const char *name; + const char *desc; + const char *extension; +} vecs_t; + +extern ff_vecs_t geo_vecs; +extern ff_vecs_t gpx_vecs; +extern ff_vecs_t mag_svecs; +extern ff_vecs_t mag_fvecs; +extern ff_vecs_t mapsend_vecs; +extern ff_vecs_t mps_vecs; +extern ff_vecs_t gpsutil_vecs; +extern ff_vecs_t tiger_vecs; +extern ff_vecs_t pcx_vecs; +extern ff_vecs_t cetus_vecs; +extern ff_vecs_t gpspilot_vecs; +extern ff_vecs_t copilot_vecs; +extern ff_vecs_t psp_vecs; +extern ff_vecs_t garmin_vecs; +extern ff_vecs_t holux_vecs; +extern ff_vecs_t xcsv_vecs; +extern ff_vecs_t tpg_vecs; +extern ff_vecs_t magnav_vec; +extern ff_vecs_t tmpro_vecs; +extern ff_vecs_t gcdb_vecs; +extern ff_vecs_t easygps_vecs; +extern ff_vecs_t quovadis_vecs; +extern ff_vecs_t gpilots_vecs; +extern ff_vecs_t saroute_vecs; +extern ff_vecs_t navicache_vecs; +extern ff_vecs_t psit_vecs; /* MRCB */ +extern ff_vecs_t shape_vecs; +extern ff_vecs_t geoniche_vecs; +extern ff_vecs_t gpl_vecs; +extern ff_vecs_t ozi_vecs; +extern ff_vecs_t nmea_vecs; +extern ff_vecs_t text_vecs; +extern ff_vecs_t palmdoc_vecs; +extern ff_vecs_t html_vecs; +extern ff_vecs_t netstumbler_vecs; +extern ff_vecs_t HsaEndeavourNavigator_vecs; +extern ff_vecs_t igc_vecs; +extern ff_vecs_t brauniger_iq_vecs; + +static +vecs_t vec_list[] = { + /* XCSV must be the first entry in this table. */ + { + &xcsv_vecs, + "xcsv", + "? Character Separated Values", + NULL + }, + { + &geo_vecs, + "geo", + "Geocaching.com .loc", + "loc" + }, + { + &gpx_vecs, + "gpx", + "GPX XML", + "gpx" + }, + { + &mag_svecs, + "magellan", + "Magellan serial protocol", + NULL + }, + { + &mag_fvecs, + "magellan", + "Magellan SD files (as for Meridians)", + NULL + }, + { + &mapsend_vecs, + "mapsend", + "Magellan Mapsend", + NULL + }, + { + &pcx_vecs, + "pcx", + "Garmin PCX5", + "pcx" + }, + { + &mps_vecs, + "mapsource", + "Garmin Mapsource", + NULL + }, + { + &gpsutil_vecs, + "gpsutil", + "gpsutil", + NULL + }, + { + &psp_vecs, + "psp", + "MS PocketStreets 2002 Pushpin", + "psp" + }, + { + &cetus_vecs, + "cetus", + "Cetus for Palm/OS", + NULL + }, + { + &copilot_vecs, + "copilot", + "CoPilot Flight Planner for Palm/OS", + NULL + }, + { + &gpspilot_vecs, + "gpspilot", + "GPSPilot Tracker for Palm/OS", + NULL + }, + { + &magnav_vec, + "magnav", + "Magellan NAV Companion for PalmOS", + NULL + }, + { + &garmin_vecs, + "garmin", + "Garmin serial protocol", + NULL + }, + { + &holux_vecs, + "holux", + "Holux (gm-100) .wpo Format", + "wpo" + }, + { + &tpg_vecs, + "tpg", + "National Geographic Topo .tpg", + "tpg" + }, + { + &tmpro_vecs, + "tmpro", + "TopoMapPro Places File", + "tmpro" + }, + { + &gcdb_vecs, + "gcdb", + "Geocaching Database", + NULL + }, + { + &tiger_vecs, + "tiger", + "U.S. Census Bureau Tiger Mapping Service", + NULL + }, + { + &easygps_vecs, + "easygps", + "EasyGPS", + NULL + }, + { + &quovadis_vecs, + "quovadis", + "Quovadis", + NULL + }, + { + &gpilots_vecs, + "gpilots", + "GpilotS", + NULL + }, + { + &saroute_vecs, + "saroute", + "Delorme Street Atlas Route", + ".anr" + }, + { + &navicache_vecs, + "navicache", + "Navicache.com XML", + NULL + }, + { /* MRCB */ + &psit_vecs, + "psitrex", + "KuDaTa PsiTrex text", + NULL + }, + { + &shape_vecs, + "shape", + "ESRI shapefile", + NULL + }, + { + &geoniche_vecs, + "geoniche", + "GeoNiche .pdb", + NULL + }, + { + &gpl_vecs, + "gpl", + "Delorme GPL", + NULL + }, + { + &ozi_vecs, + "ozi", + "OziExplorer", + NULL + }, + { + &nmea_vecs, + "nmea", + "NMEA 0183 sentences", + NULL + }, + { + &text_vecs, + "text", + "Textual Output", + NULL + }, + { + &html_vecs, + "html", + "HTML Output", + NULL + }, + { + &palmdoc_vecs, + "palmdoc", + "PalmDoc Output", + NULL + }, + { + &netstumbler_vecs, + "netstumbler", + "NetStumbler Summary File", + NULL + }, + { + &HsaEndeavourNavigator_vecs, + "hsandv", + "HSA Endeavour Navigator export File", + NULL + }, + { + &igc_vecs, + "igc", + "FAI/IGC Flight Recorder Data Format", + NULL + }, + { + &brauniger_iq_vecs, + "baroiq", + "Brauniger IQ Series Barograph Download", + NULL + }, + { + NULL, + NULL, + NULL, + NULL + } +}; + +void +exit_vecs( void ) +{ + vecs_t *vec = vec_list; + while ( vec->vec ) { + arglist_t *ap; + if ( vec->vec->exit ) { + (*vec->vec->exit)(); + } + if ( vec->vec->args ) { + for ( ap = vec->vec->args; ap->argstring; ap++ ) { + if ( ap->argval && *ap->argval ) { + xfree(*ap->argval); + *ap->argval = NULL; + } + } + } + vec++; + } +} + +ff_vecs_t * +find_vec(char *const vecname, char **opts) +{ + vecs_t *vec = vec_list; + style_vecs_t *svec = style_list; + char *v = xstrdup(vecname); + char *svecname = strtok(v, ","); + + while (vec->vec) { + arglist_t *ap; + char *res; + + if (strcmp(svecname, vec->name)) { + vec++; + continue; + } + + res = strchr(vecname, ','); + if (res) { + *opts = strchr(vecname, ',')+1; + + if (vec->vec->args) { + for (ap = vec->vec->args; ap->argstring; ap++){ + char *opt = NULL; + if ( *ap->argval ) xfree(*ap->argval); + + opt = get_option(*opts, ap->argstring); + if ( opt ) { + *ap->argval = opt; + } + else if ( ap->defaultvalue ) { + *ap->argval = xstrdup( + ap->defaultvalue ); + } + else { + *ap->argval = NULL; + } + } + } + } else { + *opts = NULL; + if (vec->vec->args) { + for (ap = vec->vec->args; ap->argstring; ap++){ + if ( *ap->argval ) xfree(*ap->argval); + + if ( ap->defaultvalue ) { + *ap->argval = xstrdup( + ap->defaultvalue ); + } + else { + *ap->argval = NULL; + } + } + } + } + + xcsv_setup_internal_style( NULL ); + xfree(v); + return vec->vec; + + } + + /* + * Didn't find it in the table of "real" file types, so plan B + * is to search the list of xcsv styles. + */ + while (svec->name) { + arglist_t *ap; + char *res; + + if (strcmp(svecname, svec->name)) { + svec++; + continue; + } + + res = strchr(vecname, ','); + if (res) { + *opts = strchr(vecname, ',') + 1; + if (vec_list[0].vec->args) { + for (ap = vec_list[0].vec->args; ap->argstring; ap++) { + *ap->argval = get_option(*opts, ap->argstring); + } + } + } else { + *opts = NULL; + } + xcsv_setup_internal_style(svec->style_buf); + + xfree(v); + + return vec_list[0].vec; + } + + /* + * Not found. + */ + xfree(v); + return NULL; +} + +/* + * Find and return a specific argument in an arg list. + * Modelled approximately after getenv. + */ +char * +#ifdef DEBUG_MEM +GET_OPTION(const char *iarglist, const char *argname, DEBUG_PARAMS) +#else +get_option(const char *iarglist, const char *argname) +#endif +{ + size_t arglen = strlen(argname); + char *arglist; + char *rval = NULL; + char *arg; + char *argp; + + if (!iarglist) { + return NULL; + } + + arglen = strlen(argname); + arglist = xstrdup(iarglist); + + for (arg = arglist; argp = strtok(arg, ","); arg = NULL) { + if (0 == strncmp(argp, argname, arglen)) { + /* + * If we have something of the form "foo=bar" + * return "bar". Otherwise, we assume we have + * simply "foo" so we return that. + */ + if (argp[arglen] == '=') + rval = argp + arglen + 1; + else + rval = argp; + break; + } + } + /* + * Return an offset into the allocated copy. + * The caller mustn't free or otherwise get froggy with + * this data. + */ + if ( rval ) { + rval = xxstrdup(rval,file, line); + } + xfree(arglist); + return rval; +} + +/* + * Display the available formats in a format that's easy for humans to + * parse for help on available command line options. + */ +static signed int +alpha (const void *a, const void *b) +{ + + const vecs_t *const *ap = a; + const vecs_t *const *bp = b; + + return strcmp((*ap)->name , (*bp)->name); +} + +void +disp_vecs(void) +{ + vecs_t *vec; + style_vecs_t *svec; + arglist_t *ap; + int vc; + vecs_t **svp; + int i = 0; + +#define VEC_FMT " %-20.20s %-.50s\n" + + /* Get a count from both the vec (normal) and the svec (csv) lists */ + + extern size_t nstyles; + vc = sizeof vec_list / sizeof vec_list[0] -1 + nstyles; + + svp = xcalloc(vc, sizeof(style_vecs_t *)); + + /* Normal vecs are easy; populate the first part of the array. */ + for (vec = vec_list; vec->vec; vec++, i++) { + svp[i] = vec; + } + /* Walk the style list, parse the entries, dummy up a "normal" vec */ + for (svec = style_list; svec->name; svec++, i++) { + xcsv_read_internal_style(svec->style_buf); + svp[i] = xcalloc(1, sizeof **svp); + svp[i]->name = svec->name; + svp[i]->vec = svp[0]->vec; /* Interits xcsv opts */ + svp[i]->desc = xcsv_file.description; + } + + /* Now that we have everything in an array, alphabetize them */ + qsort(svp, vc, sizeof(*svp), alpha); + + for (i=0;iname, svp[i]->desc); + for (ap = svp[i]->vec->args; ap && ap->argstring; ap++) { + if ( !(ap->argtype & ARGTYPE_HIDDEN)) + printf(" %-18.18s %-.50s %s\n", + ap->argstring, ap->helpstring, + (ap->argtype & ARGTYPE_REQUIRED)?"(required)":""); + } + } + + return; +} + +/* + * Additional information for V1. + * Output format type at front of line. + */ +static void +disp_v1(ff_type t) +{ + char *tstring; + + switch (t) { + case ff_type_file: tstring = "file"; break; + case ff_type_serial: tstring = "serial"; break; + case ff_type_internal: tstring = "internal"; break; + default: tstring = "unknown"; break; + } + printf("%s\t", tstring); +} +/* + * Display the available formats in a format that's easy to machine + * parse. Typically invoked by programs like graphical wrappers to + * determine what formats are supported. + */ +void +disp_formats(int version) +{ + vecs_t *vec; + style_vecs_t *svec; + + switch(version) { + case 0: + case 1: + for (vec = vec_list; vec->vec; vec++) { + if (version > 0) + disp_v1(vec->vec->type); + if (vec->vec->type == ff_type_internal) + continue; + printf("%s\t%s\t%s\n", vec->name, + vec->extension? vec->extension : "", + vec->desc); + } + for (svec = style_list; svec->name; svec++) { + xcsv_read_internal_style(svec->style_buf); + if (version > 0) + disp_v1(xcsv_file.type); + printf("%s\t%s\t%s\n", svec->name, xcsv_file.extension ? + xcsv_file.extension : "", xcsv_file.description); + } + break; + default: + ; + } +} diff --git a/vmem.c b/vmem.c new file mode 100644 index 000000000..32eda7aae --- /dev/null +++ b/vmem.c @@ -0,0 +1,67 @@ +/* + vmem utilities. Manipulate allocated object optimized for + long-term persistence over raw speed. + + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include + +vmem_t +vmem_alloc(size_t size, int flags) +{ + vmem_t vm; + /* + * By default, zero the allocated thingy. + */ + if (flags & VMFL_NOZERO) + vm.mem = xmalloc(size); + else + vm.mem = xcalloc(size, 1); + vm.size = size; + return vm; +} + +void +vmem_free(vmem_t *vm) +{ + xfree(vm->mem); + vm->mem = NULL; + vm->size = 0; + return; +} + +/* + * We never shrink a vmem object on the premise that over time, object + * will only grow for a while then reach a steady state. + */ +void +vmem_realloc(vmem_t *vm, size_t size) +{ + /* + * Reallocate only if we must. + */ + if (size > vm->size) { + vm->mem = xrealloc(vm->mem, size); + vm->size = size; + } + return; +} + + diff --git a/waypt.c b/waypt.c new file mode 100644 index 000000000..fde54f87b --- /dev/null +++ b/waypt.c @@ -0,0 +1,288 @@ +/* + Perform various operations on waypoints. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include "defs.h" + +queue waypt_head; +static unsigned int waypt_ct; +static void *mkshort_handle; + +void +waypt_init(void) +{ + mkshort_handle = mkshort_new_handle(); + QUEUE_INIT(&waypt_head); +} + +waypoint * +waypt_dupe(const waypoint *wpt) +{ + waypoint * tmp; + tmp = waypt_new(); + memcpy(tmp, wpt, sizeof(waypoint)); + + if (wpt->shortname) + tmp->shortname = xstrdup(wpt->shortname); + if (wpt->description) + tmp->description = xstrdup(wpt->description); + if (wpt->notes) + tmp->notes = xstrdup(wpt->notes); + if (wpt->url) + tmp->url = xstrdup(wpt->url); + if (wpt->url_link_text) + tmp->url_link_text = xstrdup(wpt->url_link_text); + if (wpt->icon_descr && wpt->icon_descr_is_dynamic) + tmp->icon_descr = xstrdup(wpt->icon_descr); + if (wpt->gc_data.desc_short.utfstring) { + tmp->gc_data.desc_short.utfstring = + xstrdup(tmp->gc_data.desc_short.utfstring); + } + if (wpt->gc_data.desc_long.utfstring) { + tmp->gc_data.desc_long.utfstring = + xstrdup(tmp->gc_data.desc_long.utfstring); + } + /* + * It's important that this duplicated waypoint not appear + * on the master Q. + */ + tmp->Q.next = tmp->Q.prev = NULL; + tmp->gpx_extras = NULL; + + return tmp; +} + +void +waypt_add(waypoint *wpt) +{ + ENQUEUE_TAIL(&waypt_head, &wpt->Q); + waypt_ct++; + + /* + * Some input may not have one or more of these types so we + * try to be sure that we have these fields even if just by + * copying them from elsewhere. + */ + + if (wpt->shortname == NULL) { + if (wpt->description) { + wpt->shortname = xstrdup(wpt->description); + } else if (wpt->notes) { + wpt->shortname = xstrdup(wpt->notes); + } else { + /* Last ditch: make up a name */ + char cbuf[10]; + snprintf(cbuf, sizeof(cbuf), "WPT%03d", waypt_ct); + wpt->shortname = xstrdup(cbuf); + } + } + + if (wpt->description == NULL || strlen(wpt->description) == 0) { + if (wpt->description) + xfree(wpt->description); + if (wpt->notes != NULL) { + wpt->description = xstrdup(wpt->notes); + } else { + if (wpt->shortname != NULL) { + wpt->description = xstrdup(wpt->shortname); + } + } + } +} + +void +waypt_del(waypoint *wpt) +{ + dequeue(&wpt->Q); + waypt_ct--; +} + +/* + * A constructor for a single waypoint. + */ +waypoint * +waypt_new(void) +{ + waypoint *wpt; + + wpt = (waypoint *) xcalloc(sizeof (*wpt), 1); + wpt->altitude = unknown_alt; + + return wpt; +} + +unsigned int +waypt_count(void) +{ + return waypt_ct; +} + +void +waypt_disp(const waypoint *wpt) +{ + char *tmpdesc = NULL; + if (wpt->creation_time) { + printf("%s ", ctime(&wpt->creation_time)); + } + printposn(wpt->latitude,1); + printposn(wpt->longitude,0); + + if ( wpt->description ) { + tmpdesc = str_utf8_to_ascii( wpt->description); + printf("%s/%s", + global_opts.synthesize_shortnames ? + mkshort(mkshort_handle, tmpdesc) : + wpt->shortname, + tmpdesc); + if ( tmpdesc ) + xfree(tmpdesc); + } + + if (wpt->altitude != unknown_alt) + printf(" %f", wpt->altitude); + printf("\n"); +} + +void +waypt_status_disp(int total_ct, int myct) +{ + fprintf(stdout, "%d/%d/%d\r", myct*100/total_ct, myct, total_ct); + fflush(stdout); +} + +void +waypt_disp_all(waypt_cb cb) +{ + queue *elem, *tmp; + waypoint *waypointp; + int i = 0; + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + waypointp = (waypoint *) elem; + if (global_opts.verbose_status) { + i++; + waypt_status_disp(waypt_ct, i); + } + (*cb) (waypointp); + } + if (global_opts.verbose_status) { + fprintf(stdout, "\r\n"); + } +} + +/* + * Makes another pass over the data to compute bounding + * box data and populates bounding box information. + */ + +void +waypt_compute_bounds(bounds *bounds) +{ + queue *elem, *tmp; + waypoint *waypointp; + + /* Set data out of bounds so that even one waypoint will reset */ + bounds->max_lat = -9999; + bounds->max_lon = -9999; + bounds->min_lat = 9999; + bounds->min_lon = 9999; + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + waypointp = (waypoint *) elem; + if (waypointp->latitude > bounds->max_lat) + bounds->max_lat = waypointp->latitude; + if (waypointp->longitude > bounds->max_lon) + bounds->max_lon = waypointp->longitude; + if (waypointp->latitude < bounds->min_lat) + bounds->min_lat = waypointp->latitude; + if (waypointp->longitude < bounds->min_lon) + bounds->min_lon = waypointp->longitude; + } +} + +waypoint * +find_waypt_by_name(const char *name) +{ + queue *elem, *tmp; + waypoint *waypointp; + + QUEUE_FOR_EACH(&waypt_head, elem, tmp) { + waypointp = (waypoint *) elem; + if (0 == strcmp(waypointp->shortname, name)) { + return waypointp; + } + } + + return NULL; +} + +void +waypt_free( waypoint *wpt ) +{ + if (wpt->shortname) { + xfree(wpt->shortname); + } + if (wpt->description) { + xfree(wpt->description); + } + if (wpt->notes) { + xfree(wpt->notes); + } + if (wpt->url) { + xfree(wpt->url); + } + if (wpt->url_link_text) { + xfree(wpt->url_link_text); + } + if (wpt->icon_descr && wpt->icon_descr_is_dynamic) { + xfree((char *)(void *)wpt->icon_descr); + } + if (wpt->gpx_extras) { + free_gpx_extras(wpt->gpx_extras); + } + if (wpt->gc_data.desc_short.utfstring) { + xfree(wpt->gc_data.desc_short.utfstring); + } + if (wpt->gc_data.desc_long.utfstring) { + xfree(wpt->gc_data.desc_long.utfstring); + } + xfree(wpt); +} + +void +waypt_flush( queue *head ) +{ + queue *elem, *tmp; + + QUEUE_FOR_EACH(head, elem, tmp) { + waypoint *q = (waypoint *) dequeue(elem); + waypt_free(q); + } +} + +void +waypt_flush_all() +{ + if ( mkshort_handle ) { + mkshort_del_handle( mkshort_handle ); + } + waypt_flush(&waypt_head); +} diff --git a/win32/README b/win32/README new file mode 100644 index 000000000..132c2c7ff --- /dev/null +++ b/win32/README @@ -0,0 +1,5 @@ + +This is a Windows front-end for GPSBabel. It was contributed and is +maintained by Josh McKee. It is written in Delphi. + + diff --git a/win32/gpsbabelfront.dpr b/win32/gpsbabelfront.dpr new file mode 100644 index 000000000..777008f05 --- /dev/null +++ b/win32/gpsbabelfront.dpr @@ -0,0 +1,14 @@ +program gpsbabelfront; + +uses + Forms, + gpsbabelfront_mainform in 'gpsbabelfront_mainform.pas' {FormGPSBabelFront}; + +{$R *.res} + +begin + Application.Initialize; + Application.Title := 'GPSBabel Front End'; + Application.CreateForm(TFormGPSBabelFront, FormGPSBabelFront); + Application.Run; +end. diff --git a/win32/gpsbabelfront.exe b/win32/gpsbabelfront.exe new file mode 100644 index 0000000000000000000000000000000000000000..b719d19b79ad79913b805535f897dd1285be7315 GIT binary patch literal 430080 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

<(2Xi#Fo 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 z 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 iA41xK!3-Es4IZ!n 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 literal 0 HcmV?d00001 diff --git a/win32/gpsbabelfront_mainform.dfm b/win32/gpsbabelfront_mainform.dfm new file mode 100644 index 000000000..7721ba5c3 --- /dev/null +++ b/win32/gpsbabelfront_mainform.dfm @@ -0,0 +1,156 @@ +object FormGPSBabelFront: TFormGPSBabelFront + Left = 208 + Top = 103 + BorderStyle = bsDialog + Caption = 'GPSBabel GUI Frontend' + ClientHeight = 312 + ClientWidth = 369 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnCreate = FormCreate + DesignSize = ( + 369 + 312) + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 8 + Top = 292 + Width = 250 + Height = 13 + Anchors = [akLeft, akBottom] + Caption = 'GPSBabel: http://sourceforge.net/projects/gpsbabel' + end + object Label2: TLabel + Left = 8 + Top = 16 + Width = 43 + Height = 13 + Caption = 'Input file:' + end + object Label3: TLabel + Left = 8 + Top = 80 + Width = 51 + Height = 13 + Caption = 'Output file:' + end + object Bevel1: TBevel + Left = -3 + Top = 285 + Width = 380 + Height = 2 + Anchors = [akLeft, akBottom] + end + object Label4: TLabel + Left = 16 + Top = 104 + Width = 35 + Height = 13 + Caption = 'Format:' + end + object Label5: TLabel + Left = 16 + Top = 40 + Width = 35 + Height = 13 + Caption = 'Format:' + end + object Label6: TLabel + Left = 8 + Top = 168 + Width = 33 + Height = 13 + Caption = 'Result:' + end + object comboInput: TComboBox + Left = 64 + Top = 40 + Width = 297 + Height = 21 + Style = csDropDownList + ItemHeight = 13 + TabOrder = 2 + end + object editInput: TEdit + Left = 64 + Top = 16 + Width = 273 + Height = 21 + TabOrder = 0 + end + object editOutput: TEdit + Left = 64 + Top = 80 + Width = 273 + Height = 21 + TabOrder = 3 + end + object comboOutput: TComboBox + Left = 64 + Top = 104 + Width = 297 + Height = 21 + Style = csDropDownList + ItemHeight = 13 + TabOrder = 5 + end + object btnProcess: TButton + Left = 288 + Top = 136 + Width = 75 + Height = 25 + Caption = 'Process' + TabOrder = 7 + OnClick = btnProcessClick + end + object cbIgnoreShort: TCheckBox + Left = 64 + Top = 136 + Width = 169 + Height = 17 + Caption = 'Ignore "short" names' + TabOrder = 6 + end + object btnInput: TButton + Left = 341 + Top = 16 + Width = 19 + Height = 21 + Caption = '...' + TabOrder = 1 + OnClick = btnInputClick + end + object btnOutput: TButton + Left = 341 + Top = 80 + Width = 19 + Height = 21 + Caption = '...' + TabOrder = 4 + OnClick = btnOutputClick + end + object memoStdErr: TMemo + Left = 64 + Top = 168 + Width = 297 + Height = 113 + Color = clBtnHighlight + ReadOnly = True + TabOrder = 8 + end + object OpenDialogInput: TOpenDialog + Left = 248 + Top = 192 + end + object SaveDialogOutput: TSaveDialog + Left = 248 + Top = 240 + end +end diff --git a/win32/gpsbabelfront_mainform.pas b/win32/gpsbabelfront_mainform.pas new file mode 100644 index 000000000..4507e12ab --- /dev/null +++ b/win32/gpsbabelfront_mainform.pas @@ -0,0 +1,384 @@ +{ + + Copyright (C) 2002 Josh M. McKee, mrsnazz@users.sourceforge.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + +} + +{ + 1.0.0 JMc First release + 1.0.1 JMc - Switched to using AddFormat for populating the formats table + - Updated formats table to include currently supported formats + - Switched to using CreateProcess rather than WinExec, so that + we can display data from stderr to the user. + 1.0.2 JMc - Added LoadFormats to call the new -^ switch, to dynamically + load the supported formats from gpsbabel.exe. +} + +unit gpsbabelfront_mainform; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, ExtCtrls, StdCtrls; + +type + TFormat = record + sType:string; // type to be passed to GPSBabel + sExt:string; // default file extension + sDesc:string; // description of format + end; + + TFormGPSBabelFront = class(TForm) + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + comboInput: TComboBox; + editInput: TEdit; + editOutput: TEdit; + comboOutput: TComboBox; + btnProcess: TButton; + cbIgnoreShort: TCheckBox; + Bevel1: TBevel; + btnInput: TButton; + btnOutput: TButton; + OpenDialogInput: TOpenDialog; + SaveDialogOutput: TSaveDialog; + Label4: TLabel; + Label5: TLabel; + memoStdErr: TMemo; + Label6: TLabel; + procedure FormCreate(Sender: TObject); + procedure btnInputClick(Sender: TObject); + procedure btnOutputClick(Sender: TObject); + procedure btnProcessClick(Sender: TObject); + public + formats:array of TFormat; + nFormatCount:integer; + + procedure LoadFormats; + procedure AddFormat(sType,sExt,sDesc:string); + + procedure PopulateCombos; + procedure PopulateDialogs; + end; + +var + FormGPSBabelFront: TFormGPSBabelFront; + +implementation + +{$R *.dfm} + +procedure TFormGPSBabelFront.AddFormat(sType,sExt,sDesc:string); +begin + SetLength(formats,nFormatCount+1); + + formats[nFormatCount].sType := sType; + formats[nFormatCount].sExt := sExt; + formats[nFormatCount].sDesc := sDesc; + + inc(nFormatCount); +end; + +procedure TFormGPSBabelFront.PopulateCombos; +var + i:integer; +begin + for i:=0 to nFormatCount-1 do begin + comboInput.items.add(formats[i].sDesc); + comboOutput.items.add(formats[i].sDesc); + end; +end; + +procedure TFormGPSBabelFront.PopulateDialogs; +var + i:integer; +begin + OpenDialogInput.Filter := ''; + SaveDialogOutput.Filter := ''; + for i:=0 to nFormatCount-1 do begin + if (formats[i].sExt<>'') then begin + OpenDialogInput.Filter := OpenDialogInput.Filter + formats[i].sDesc + ' (*.' + + formats[i].sExt + ')|*.' + uppercase(formats[i].sExt) + '|'; + + SaveDialogOutput.Filter := SaveDialogOutput.Filter + formats[i].sDesc + ' (*.' + + formats[i].sExt + ')|*.' + uppercase(formats[i].sExt) + '|'; + end; + end; + + OpenDialogInput.Filter := OpenDialogInput.Filter + 'All files (*.*)|*.*'; + SaveDialogOutput.Filter := SaveDialogOutput.Filter + 'All files (*.*)|*.*'; +end; + +procedure TFormGPSBabelFront.FormCreate(Sender: TObject); +begin + nFormatCount := 0; + + // load formats from GPSBabel.exe + LoadFormats; + + if nFormatCount = 0 then begin + ShowMessage('Unable to load format list from GPSBabel.exe. Default format list is being used instead.'); + + // add the default formats + AddFormat('geo','loc','Geocaching.com .loc'); + AddFormat('gpsman','','GPSman'); + AddFormat('gpx','gpx','GPX XML'); + AddFormat('magellan','','Magellan protocol'); + AddFormat('mapsend','','Magellan Mapsend'); + AddFormat('pcx','pcx','Garmin PCX5'); + AddFormat('mapsource','','Garmin Mapsource'); + AddFormat('gpsutil','','gpsutil'); + AddFormat('tiger','','U.S. Census Bureau Tiger Mapping Service'); + AddFormat('csv','csv','Comma seperated values'); + AddFormat('xmap','','Delorme Topo USA4/XMap Conduit'); + AddFormat('dna','dna','Navitrak DNA marker format'); + AddFormat('psp','psp','MS PocketStreets 2002 Pushpin'); + AddFormat('cetus','','Cetus for Palm/OS'); + AddFormat('gpspilot','','GPSPilot Tracker for Palm/OS'); + AddFormat('magnav','','Magellan NAV Companion for PalmOS'); + AddFormat('garmin','','Garmin serial protocol'); + AddFormat('mxf','mxf','MapTech Exchange Format'); + AddFormat('holux','wpo','Holux (gm-100) .wpo Format'); + AddFormat('ozi','ozi','OziExplorer Waypoint'); + AddFormat('tpg','tpg','National Geographic Topo .tpg'); + AddFormat('tmpro','tmpro','TopoMapPro Places File'); + end; + + // Set up the dropdown lists and open/save dialog filters using the formats + PopulateCombos; + PopulateDialogs; +end; + +procedure TFormGPSBabelFront.btnInputClick(Sender: TObject); +var + sExt:string; + i:integer; +begin + if opendialoginput.Execute then begin + editInput.Text := opendialoginput.filename; + sExt := uppercase(ExtractFileExt(editInput.text)); + for i := 0 to nFormatCount-1 do begin + if '.' + uppercase(formats[i].sExt) = sExt then comboInput.ItemIndex := i; + end; + end; +end; + +procedure TFormGPSBabelFront.btnOutputClick(Sender: TObject); +var + sExt:string; + i:integer; +begin + if savedialogoutput.Execute then begin + editOutput.Text := savedialogoutput.filename; + sExt := uppercase(ExtractFileExt(editOutput.text)); + for i := 0 to nFormatCount-1 do begin + if '.' + uppercase(formats[i].sExt) = sExt then comboOutput.ItemIndex := i; + end; + end; +end; + +procedure TFormGPSBabelFront.LoadFormats; +var + sIgnoreShort:string; + sCmd:string; + f:file; + Buffer:array[0..255] of char; + hRead,hWrite:THandle; + StartupInfo:TStartupInfo; + ProcessInfo:TProcessInformation; + saAttr:TSecurityAttributes; + OutSt:TMemoryStream; + dwRead:DWord; + dwExitCode:cardinal; + overlapped:TOverlapped; + slstFormats:TStringList; + i:integer; + + procedure ExtractFormat(sFormat:string); + var + toks:array[0..2] of string; + i,nTok,nLen:integer; + begin + i := 1; + nTok := 0; + toks[0] := ''; + toks[1] := ''; + toks[2] := ''; + nLen := length(sFormat); + while ((i<=nLen) and (nTok<3)) do begin + if sFormat[i]=#9 then begin + inc(nTok); + end else begin + toks[nTok] := toks[nTok] + sFormat[i]; + end; + inc(i); + end; + {showmessage(toks[0]); + showmessage(toks[1]); + showmessage(toks[2]);} + + AddFormat(toks[0],toks[1],toks[2]); + end; + +begin + slstFormats := TStringList.Create; + + sCmd := 'GPSBabel -^'; + + memoStdErr.lines.clear; + + saAttr.nLength := sizeof(TSECURITYATTRIBUTES); + saAttr.bInheritHandle := true; + saAttr.lpSecurityDescriptor := nil; + + if not CreatePipe(hRead, hWrite,@saAttr,0) then begin + ShowMessage('Unable to create pipe!'); + Exit; + end; + + AllocConsole; + + FillChar(StartupInfo,Sizeof(StartupInfo),#0); + StartupInfo.cb := Sizeof(StartupInfo); + StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; + StartupInfo.wShowWindow := SW_HIDE and SW_SHOWMINNOACTIVE; + StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE); + StartupInfo.hStdOutput:= hWrite; + StartupInfo.hStdError := hWrite; + + if not CreateProcess(nil,pchar(sCmd),nil,nil,true,CREATE_NEW_CONSOLE,nil,nil,StartupInfo,ProcessInfo) then begin + ShowMessage('Unable to execute GPSBabel.exe.') + end else begin + while (WaitforSingleObject(ProcessInfo.hProcess,0)) <> WAIT_OBJECT_0 do; + + PeekNamedPipe(hRead,nil,0,nil,@dwRead,nil); + + if dwRead>0 then begin + OutSt := TMemoryStream.Create; + + repeat + if ReadFile(hRead, Buffer, 80, dwRead, nil) then begin + OutSt.WriteBuffer(Buffer, dwRead) + end; + until dwRead<>80; + + OutSt.Seek(0,0); + slstFormats.LoadFromStream(OutSt); + for i:=0 to slstFormats.count-1 do begin + ExtractFormat(slstFormats[i]); + end; + OutSt.Free; + end else memoStdErr.lines.add('Command executed successfully.'); + end; + + CloseHandle(hRead); CloseHandle(hWrite); + FreeConsole; +end; + +procedure TFormGPSBabelFront.btnProcessClick(Sender: TObject); +var + sIgnoreShort:string; + sCmd:string; + f:file; + Buffer:array[0..255] of char; + hRead,hWrite:THandle; + StartupInfo:TStartupInfo; + ProcessInfo:TProcessInformation; + saAttr:TSecurityAttributes; + OutSt:TMemoryStream; + dwRead:DWord; + dwExitCode:cardinal; + overlapped:TOverlapped; +begin + if (comboInput.ItemIndex)<0 then begin + ShowMessage('You must select the input file format.'); + exit; + end; + + if (comboOutput.ItemIndex)<0 then begin + ShowMessage('You must select the output file format.'); + exit; + end; + + if cbIgnoreShort.checked then sIgnoreShort := '-s' else sIgnoreShort := ''; + + // The output file must exist, or else ExtractShortPathName will not function + if not fileexists(editoutput.text) then begin + system.assign(f,editoutput.text); + system.rewrite(f); + system.close(f); + end; + + // Construct the command line to execute gpsbabel.exe. ExtractShortPathName + // is used to reduce any "long" file/directory names in the paths down to + // 8.3 dos format names (this removes spaces, etc). + sCmd := 'GPSBabel '+sIgnoreShort+' -i '+formats[comboInput.itemindex].sType+' -f '+ + ExtractShortPathName(editInput.text)+' -o '+formats[comboOutput.itemindex].sType+' -F '+ + ExtractShortPathName(editOutput.text); + + memoStdErr.lines.clear; + + saAttr.nLength := sizeof(TSECURITYATTRIBUTES); + saAttr.bInheritHandle := true; + saAttr.lpSecurityDescriptor := nil; + + if not CreatePipe(hRead, hWrite,@saAttr,0) then begin + ShowMessage('Unable to create pipe!'); + Exit; + end; + + AllocConsole; + + FillChar(StartupInfo,Sizeof(StartupInfo),#0); + StartupInfo.cb := Sizeof(StartupInfo); + StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; + StartupInfo.wShowWindow := SW_HIDE and SW_SHOWMINNOACTIVE; + StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE); + StartupInfo.hStdOutput:= hWrite; + StartupInfo.hStdError := hWrite; + + if not CreateProcess(nil,pchar(sCmd),nil,nil,true,CREATE_NEW_CONSOLE,nil,nil,StartupInfo,ProcessInfo) then begin + ShowMessage('Unable to execute GPSBabel.exe.') + end else begin + while (WaitforSingleObject(ProcessInfo.hProcess,0)) <> WAIT_OBJECT_0 do; + + PeekNamedPipe(hRead,nil,0,nil,@dwRead,nil); + + if dwRead>0 then begin + OutSt := TMemoryStream.Create; + + repeat + if ReadFile(hRead, Buffer, 80, dwRead, nil) then begin + OutSt.WriteBuffer(Buffer, dwRead) + end; + until dwRead<>80; + + OutSt.Seek(0,0); + memoStdErr.lines.LoadFromStream(OutSt); + OutSt.Free; + end else memoStdErr.lines.add('Command executed successfully.'); + end; + + CloseHandle(hRead); CloseHandle(hWrite); + FreeConsole; +end; + +end. + + diff --git a/xcsv.c b/xcsv.c new file mode 100644 index 000000000..80f2ff58f --- /dev/null +++ b/xcsv.c @@ -0,0 +1,573 @@ +/* + XCSV - X Character Separated Values (.???) + + A hopefully not too feeble attempt at parsing whatever separated values + files into the waypoint structure and back out again. This is a config- + file wrapper around csv_util.c. + + Copyright (C) 2002 Alex Mottram (geo_alexm at cox-internet.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include "defs.h" +#include "csv_util.h" + +#define MYNAME "XCSV" +#define ISSTOKEN(a,b) (strncmp(a,b, strlen(b)) == 0) + +static char *styleopt = NULL; +static char *snlenopt = NULL; +static char *snwhiteopt = NULL; +static char *snupperopt = NULL; +static char *snuniqueopt = NULL; +char *prefer_shortnames = NULL; +char *xcsv_urlbase = NULL; + +static const char *intstylebuf = NULL; + +static +arglist_t xcsv_args[] = { + {"style", &styleopt, "Full path to XCSV style file", NULL, + ARGTYPE_FILE | ARGTYPE_REQUIRED }, + {"snlen", &snlenopt, "Max synthesized shortname length", NULL, + ARGTYPE_INT}, + {"snwhite", &snwhiteopt, "(0/1) Allow whitespace synth. shortnames", + NULL, ARGTYPE_BOOL}, + {"snupper", &snupperopt, "(0/1) UPPERCASE synth. shortnames", + NULL, ARGTYPE_BOOL}, + {"snunique", &snuniqueopt, "(0/1) Make synth. shortnames unique", + NULL, ARGTYPE_BOOL}, + {"urlbase", &xcsv_urlbase, "Basename prepended to URL on output", + NULL, ARGTYPE_STRING}, + {"prefer_shortnames", &prefer_shortnames, + "Use shortname instead of description", + NULL, ARGTYPE_BOOL }, + {0, 0, 0, 0, 0} +}; + +/* a table of config file constants mapped to chars */ +static +char_map_t xcsv_char_table[] = { + { "COMMA", "," }, + { "COMMASPACE", ", " }, + { "SINGLEQUOTE", "'" }, + { "DOUBLEQUOTE", "\"" }, + { "COLON", ":" }, + { "SEMICOLON", ";" }, + { "NEWLINE", "\n" }, + { "CR", "\n" }, + { "CRNEWLINE", "\r\n" }, + { "TAB", "\t" }, + { "SPACE", " " }, + { "HASH", "#" }, + { "WHITESPACE", "\\w" }, + { NULL, NULL } +}; + +void +xcsv_destroy_style(void) +{ + queue *elem, *tmp; + field_map_t *fmp; + ogue_t *ogp; + int internal = 0; + + /* + * If this xcsv_file struct came from a file we can free it all. + * If not, we can at least free the queue elements. + */ + + /* destroy the prologue */ + QUEUE_FOR_EACH(&xcsv_file.prologue, elem, tmp) { + ogp = (ogue_t *)elem; + if (ogp->val) + xfree(ogp->val); + if (elem) + xfree(elem); + } + + /* destroy the epilogue */ + QUEUE_FOR_EACH(&xcsv_file.epilogue, elem, tmp) { + ogp = (ogue_t *)elem; + if (ogp->val) + xfree(ogp->val); + if (elem) + xfree(elem); + } + + /* destroy the ifields */ + QUEUE_FOR_EACH(&xcsv_file.ifield, elem, tmp) { + fmp = (field_map_t *) elem; + if (fmp->key) + xfree(fmp->key); + if (fmp->val) + xfree(fmp->val); + if (fmp->printfc) + xfree(fmp->printfc); + if (elem) + xfree(elem); + } + + /* destroy the ofields, if they are not re-mapped to ifields. */ + if (xcsv_file.ofield != &xcsv_file.ifield) { + QUEUE_FOR_EACH(xcsv_file.ofield, elem, tmp) { + fmp = (field_map_t *) elem; + if (fmp->key) + xfree(fmp->key); + if (fmp->val) + xfree(fmp->val); + if (fmp->printfc) + xfree(fmp->printfc); + if (elem) + xfree(elem); + } + + if (xcsv_file.ofield) + xfree(xcsv_file.ofield); + } + + /* other alloc'd glory */ + if (xcsv_file.field_delimiter) + xfree(xcsv_file.field_delimiter); + + if (xcsv_file.record_delimiter) + xfree(xcsv_file.record_delimiter); + + if (xcsv_file.badchars) + xfree(xcsv_file.badchars); + + if (xcsv_file.description) + xfree(xcsv_file.description); + + if (xcsv_file.extension) + xfree(xcsv_file.extension); + + if (xcsv_file.mkshort_handle) + xfree(xcsv_file.mkshort_handle); + + /* return everything to zeros */ + internal = xcsv_file.is_internal; + memset(&xcsv_file, '\0', sizeof(xcsv_file)); + xcsv_file.is_internal = internal; +} + +static const char * +get_char_from_constant_table(char *key) +{ + char_map_t *cm = xcsv_char_table; + + while ((cm->key) && (strcmp(key, cm->key) != 0)) { + cm++; + } + + return (cm->chars); +} + +static void +xcsv_parse_style_line(const char *sbuff) +{ + int i, linecount = 0; + char *s, *p, *sp; + const char *cp; + char *key, *val, *pfc; + + /* + * tokens should be parsed longest to shortest, unless something + * requires a previously set value. This way something like + * SHORT and SHORTNAME don't collide. + */ + + /* whack off any comments */ + if ((p = strchr(sbuff, '#')) != NULL) { + if ((p > sbuff) && p[-1] == '\\') { + memmove(p-1, p, strlen(p)); + p[strlen(p)-1] = '\0'; + } else { + *p = '\0'; + } + } + + if (strlen(sbuff)) { + if (ISSTOKEN(sbuff, "FIELD_DELIMITER")) { + sp = csv_stringtrim(&sbuff[16], "\"", 1); + cp = get_char_from_constant_table(sp); + if (cp) { + xcsv_file.field_delimiter = xstrdup(cp); + xfree(sp); + } + else + xcsv_file.field_delimiter = sp; + + p = csv_stringtrim(xcsv_file.field_delimiter, " ", 0); + + /* field delimiters are always bad characters */ + if (xcsv_file.badchars) { + xcsv_file.badchars = (char *) xrealloc(xcsv_file.badchars, + strlen(xcsv_file.badchars) + + strlen(p) + 1); + } else { + xcsv_file.badchars = (char *) xcalloc(strlen(p) + 1, 1); + } + + strcat(xcsv_file.badchars, p); + + xfree(p); + + } else + + if (ISSTOKEN(sbuff, "RECORD_DELIMITER")) { + sp = csv_stringtrim(&sbuff[17], "\"", 1); + cp = get_char_from_constant_table(sp); + if (cp) { + xcsv_file.record_delimiter = xstrdup(cp); + xfree(sp); + } + else + xcsv_file.record_delimiter = sp; + + p = csv_stringtrim(xcsv_file.record_delimiter, " ", 0); + + /* record delimiters are always bad characters */ + if (xcsv_file.badchars) { + xcsv_file.badchars = (char *) xrealloc(xcsv_file.badchars, + strlen(xcsv_file.badchars) + + strlen(p) + 1); + } else { + xcsv_file.badchars = (char *) xcalloc(strlen(p) + 1, 1); + } + + strcat(xcsv_file.badchars, p); + + xfree(p); + + } else + + if (ISSTOKEN(sbuff, "FORMAT_TYPE")) { + const char *p; + for (p = &sbuff[11]; *p && isspace(*p); p++) { + ; + } + if (ISSTOKEN(p, "INTERNAL")) { + xcsv_file.type = ff_type_internal; + } + /* this is almost inconcievable... */ + if (ISSTOKEN(p, "SERIAL")) { + xcsv_file.type = ff_type_serial; + } + } else + + if (ISSTOKEN(sbuff, "DESCRIPTION")) { + xcsv_file.description = csv_stringtrim(&sbuff[11],"", 0); + } else + + if (ISSTOKEN(sbuff, "EXTENSION")) { + xcsv_file.extension = csv_stringtrim(&sbuff[10],"", 0); + } else + + if (ISSTOKEN(sbuff, "SHORTLEN")) { + if (xcsv_file.mkshort_handle) + setshort_length(xcsv_file.mkshort_handle, atoi(&sbuff[9])); + } else + + if (ISSTOKEN(sbuff, "SHORTWHITE")) { + if (xcsv_file.mkshort_handle) + setshort_whitespace_ok(xcsv_file.mkshort_handle, atoi(&sbuff[12])); + } else + + if (ISSTOKEN(sbuff, "BADCHARS")) { + sp = csv_stringtrim(&sbuff[9], "\"", 1); + cp = get_char_from_constant_table(sp); + + if (cp) { + p = xstrdup(cp); + xfree(sp); + } + else + p = sp; + + if (xcsv_file.badchars) { + xcsv_file.badchars = (char *) xrealloc(xcsv_file.badchars, + strlen(xcsv_file.badchars) + + strlen(p) + 1); + } else { + xcsv_file.badchars = (char *) xcalloc(strlen(p) + 1, 1); + } + + strcat(xcsv_file.badchars, p); + + xfree(p); + + } else + + if (ISSTOKEN(sbuff, "PROLOGUE")) { + xcsv_prologue_add(xstrdup(&sbuff[9])); + } else + + if (ISSTOKEN(sbuff, "EPILOGUE")) { + xcsv_epilogue_add(xstrdup(&sbuff[9])); + } else + + if (ISSTOKEN(sbuff, "IFIELD")) { + key = val = pfc = NULL; + + s = csv_lineparse(&sbuff[6], ",", "", linecount); + + i = 0; + while (s) { + switch(i) { + case 0: + /* key */ + key = csv_stringtrim(s, "\"", 1); + break; + case 1: + /* default value */ + val = csv_stringtrim(s, "\"", 1); + break; + case 2: + /* printf conversion */ + pfc = csv_stringtrim(s, "\"", 1); + break; + default: + break; + } + i++; + + s = csv_lineparse(NULL, ",", "", linecount); + } + + xcsv_ifield_add(key, val, pfc); + + } else + + /* + * as OFIELDs are implemented as an after-thought, I'll + * leave this as it's own parsing for now. We could + * change the world on ifield vs ofield format later.. + */ + if (ISSTOKEN(sbuff, "OFIELD")) { + key = val = pfc = NULL; + + s = csv_lineparse(&sbuff[6], ",", "", linecount); + + i = 0; + while (s) { + switch(i) { + case 0: + /* key */ + key = csv_stringtrim(s, "\"", 1); + break; + case 1: + /* default value */ + val = csv_stringtrim(s, "\"", 1); + break; + case 2: + /* printf conversion */ + pfc = csv_stringtrim(s, "\"", 1); + break; + default: + break; + } + i++; + s = csv_lineparse(NULL, ",", "", linecount); + } + + xcsv_ofield_add(key, val, pfc); + } + } +} + + +/* + * A wrapper for xcsv_parse_style_line that reads until it hits + * a terminating null. Makes multiple calls to that function so + * that "ignore to end of line" comments work right. + */ +static void +xcsv_parse_style_buff(const char *sbuff) +{ + char ibuf[256]; + char *ibufp; + size_t i; + + while (*sbuff) { + ibuf[0] = 0; + i = 0; + for (ibufp = ibuf; *sbuff != '\n' && i++ < sizeof(ibuf); ) { + *ibufp++ = *sbuff++; + } + while (*sbuff == '\n' || *sbuff == '\r') + sbuff++; + *ibufp = 0; + xcsv_parse_style_line(ibuf); + } +} + +static void +xcsv_read_style(const char *fname) +{ + char sbuff[8192]; + FILE *fp; + + xcsv_file_init(); + + fp = xfopen(fname, "r", MYNAME); + + do { + memset(sbuff, '\0', sizeof(sbuff)); + fgets(sbuff, sizeof(sbuff), fp); + rtrim(sbuff); + xcsv_parse_style_line(sbuff); + } while (!feof(fp)); + + /* if we have no output fields, use input fields as output fields */ + if (xcsv_file.ofield_ct == 0) { + if (xcsv_file.ofield) + xfree(xcsv_file.ofield); + xcsv_file.ofield = &xcsv_file.ifield; + xcsv_file.ofield_ct = xcsv_file.ifield_ct; + } + + fclose(fp); +} + +/* + * Passed a pointer to an internal buffer that would be identical + * to the series of bytes that would be in a style file, we set up + * the xcsv parser and make it ready for general use. + */ +void +xcsv_read_internal_style(const char *style_buf) +{ + xcsv_file_init(); + xcsv_file.is_internal = 1; + + xcsv_parse_style_buff(style_buf); + + /* if we have no output fields, use input fields as output fields */ + if (xcsv_file.ofield_ct == 0) { + if (xcsv_file.ofield) + xfree(xcsv_file.ofield); + xcsv_file.ofield = &xcsv_file.ifield; + xcsv_file.ofield_ct = xcsv_file.ifield_ct; + } +} + +void +xcsv_setup_internal_style(const char *style_buf) +{ + xcsv_file_init(); + xcsv_destroy_style(); + xcsv_file.is_internal = !!style_buf; + intstylebuf = style_buf; +} + + +static void +xcsv_rd_init(const char *fname) +{ + + /* + * if we don't have an internal style defined, we need to + * read it from a user-supplied style file, or die trying. + */ + if (xcsv_file.is_internal ) { + xcsv_read_internal_style( intstylebuf ); + } + else { + if (!styleopt) + fatal(MYNAME ": XCSV input style not declared. Use ... -i xcsv,style=path/to/file.style\n"); + + xcsv_read_style(styleopt); + } + + if (global_opts.masked_objective & (TRKDATAMASK|RTEDATAMASK)) { + warning(MYNAME "attempting to read %s as a track or route. Converting to waypoints.\n", fname); + } + + xcsv_file.xcsvfp = xfopen(fname, "r", MYNAME); + +} + +static void +xcsv_rd_deinit(void) +{ + fclose(xcsv_file.xcsvfp); + + xcsv_destroy_style(); +} + +static void +xcsv_wr_init(const char *fname) +{ + /* if we don't have an internal style defined, we need to + * read it from a user-supplied style file, or die trying. + */ + if (xcsv_file.is_internal ) { + xcsv_read_internal_style( intstylebuf ); + } + else { + + if (!styleopt) + fatal(MYNAME ": XCSV output style not declared. Use ... -o xcsv,style=path/to/file.style\n"); + + xcsv_read_style(styleopt); + } + + xcsv_file.xcsvfp = xfopen(fname, "w", MYNAME); + xcsv_file.fname = (char *)fname; + + /* set mkshort options from the command line */ + if (global_opts.synthesize_shortnames) { + + if (snlenopt) + setshort_length(xcsv_file.mkshort_handle, atoi(snlenopt)); + + if (snwhiteopt) + setshort_whitespace_ok(xcsv_file.mkshort_handle, atoi(snwhiteopt)); + + if (snupperopt) + setshort_mustupper(xcsv_file.mkshort_handle, atoi(snupperopt)); + + if (snuniqueopt) + setshort_mustuniq(xcsv_file.mkshort_handle, atoi(snuniqueopt)); + + setshort_badchars(xcsv_file.mkshort_handle, xcsv_file.badchars); + + } + +} + +static void +xcsv_wr_deinit(void) +{ + fclose(xcsv_file.xcsvfp); + + xcsv_destroy_style(); +} + +ff_vecs_t xcsv_vecs = { + ff_type_internal, + xcsv_rd_init, + xcsv_wr_init, + xcsv_rd_deinit, + xcsv_wr_deinit, + xcsv_data_read, + xcsv_data_write, + NULL, + xcsv_args +}; -- 2.30.2

    +
  • shapelib.html: This file - general documentation on the +Shapefile C Library.

    + +

  • shp_api.html: Documentation +for the API for accessing the .shp/.shx files.

    + +

  • dbf_api.html: Documentation +for the API for accessing the .dbf attribute files.

    + +

  • shpopen.c: C code for access to .shp/.shx vertex files.

    + +

  • dbfopen.c: C code for access to .dbf attribute file.

    + +

  • shapefil.h: Include file defining all the services of dbfopen.c +and shpopen.c.

    + +

  • contrib/: A directory of "in progress" contributed programs +from Carl Anderson.

    + +

  • dbfcreate.c: Simple example program for creating a new .dbf file. +

    + +

  • dbfadd.c: + Simple example program for adding a record to a .dbf file.

    + +

  • dbfdump.c: Simple example program for displaying the contents of + a .dbf file.

    + +

  • shpcreate.c: Simple example program for creating a new .shp and +.shx file.

    + +

  • shpadd.c: Simple example program for adding a shape to an existing + shape file.

    + +

  • shpdump.c: Simple program for dumping all the vertices in a + shapefile with an indicating of the parts.

    + +

  • shputils.c: Complex contributed program capable of clipping and + appending + shapefiles as well as a few other things. Type shputils + after building to get a full usage message.

    + +

  • Makefile: A simple makefile to compile the library and example + programs.

    + +

  • makeshape.sh: A simple script for running some of the example +programs.

    + +

  • shptest.c: A simple test harnass to generate each of the supported + types of shapefiles.

    + + +

  • shptree.c: Implements a simple quadtree algorithm for fast +spatial searches of shapefiles.

    + +

  • shptreedump.c: A simple mainly showing information on quad +trees build using the quad tree api.

    + +

  • stream1.sh - A test script, which should produce stream1.out. +Note this will only work if you have the example data downloaded.

    + +

  • stream1.out: Expected output of stream1.sh test script.

    + +

  • stream2.sh: A test script, which should produce stream2.out.

    + +

  • stream2.out: Expected output of stream2.sh test script.

    + +

  • pyshapelib-0.1: Prototype contributed Python bindings.

    + +